Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
acfa7d2269 | ||
|
|
8f62fb7877 | ||
|
|
94409dd8e1 | ||
|
|
ac25326d24 | ||
|
|
34bdbe4709 | ||
|
|
8d98aca496 | ||
|
|
ec9ad1d309 | ||
|
|
a97195c57e | ||
|
|
22a1d92191 | ||
|
|
35596249b4 | ||
|
|
566c588377 | ||
|
|
9ab49d1431 | ||
|
|
f5a7132421 | ||
|
|
c66b315623 | ||
|
|
76ba4e917e | ||
|
|
d0da79bf56 | ||
|
|
66bf3f1578 | ||
|
|
6a358883f9 | ||
|
|
86622f83d0 | ||
|
|
66c3945bc4 | ||
|
|
38cb002ce8 | ||
|
|
36443fd838 | ||
|
|
8cc451546d | ||
|
|
1bdd923365 | ||
|
|
d5610de826 | ||
|
|
aaf85943a8 | ||
|
|
37ad0ac9eb | ||
|
|
eb2791e206 | ||
|
|
119cde65c7 | ||
|
|
cb66c22974 | ||
|
|
96c5d0d86f | ||
|
|
2d98f57b65 | ||
|
|
3e2fe721d3 | ||
|
|
52fd2f712c | ||
|
|
ad6b9f470f | ||
|
|
765f672bf5 | ||
|
|
67a5d75283 | ||
|
|
4ff010e14b | ||
|
|
1214b6ecf6 | ||
|
|
aababb8075 | ||
|
|
3b0406c5af | ||
|
|
6772f066ee | ||
|
|
d8df40816f | ||
|
|
f9bd61af49 | ||
|
|
bcdda8b751 | ||
|
|
dcb44d27fe | ||
|
|
799283fd46 | ||
|
|
d0f4939a4d | ||
|
|
d66f10e715 | ||
|
|
e421eb4244 | ||
|
|
ce16bf5aa4 | ||
|
|
3582499a3c | ||
|
|
1946000d14 | ||
|
|
01fa030ef9 | ||
|
|
90cf136b8c | ||
|
|
ee131c3681 | ||
|
|
85accf7c25 | ||
|
|
91426a89e5 | ||
|
|
d7e492cdc9 | ||
|
|
c5cad1dca6 | ||
|
|
85aa7a37b9 | ||
|
|
b87fad23d8 | ||
|
|
68ec7ee5d8 | ||
|
|
e33463b371 | ||
|
|
d4b80cf90b | ||
|
|
d7e32e9b03 | ||
|
|
449fb3ac36 | ||
|
|
1de92cd2e9 | ||
|
|
fdd3e7f971 | ||
|
|
6eece7172a | ||
|
|
5b2c25d8ee | ||
|
|
40c2bfa535 | ||
|
|
a10023fad6 | ||
|
|
0a1afa988e | ||
|
|
97b884f119 | ||
|
|
eb9b7159d4 | ||
|
|
65a53388bb | ||
|
|
2ca3eb5685 | ||
|
|
a4c817cd30 | ||
|
|
d5b03c09db | ||
|
|
0b9ebade38 | ||
|
|
ee1758a548 | ||
|
|
a2a45ac898 | ||
|
|
59d172765d | ||
|
|
d453ff809a | ||
|
|
ed0a99dbd9 | ||
|
|
32f31cb502 | ||
|
|
176d554ef9 | ||
|
|
2735c37fad | ||
|
|
f04ec36faf | ||
|
|
28f0ca4337 | ||
|
|
1dbf0b07b6 | ||
|
|
27ed4e58bd | ||
|
|
a7f56c0bd5 | ||
|
|
284ccd43f8 | ||
|
|
5a66153dfc | ||
|
|
363981a2f7 | ||
|
|
7848aa2f0c | ||
|
|
0a7b653ec8 | ||
|
|
313c4dbb71 | ||
|
|
1927323fb7 | ||
|
|
41f11f3040 | ||
|
|
9833628867 | ||
|
|
4dd911e73d | ||
|
|
56487d3832 | ||
|
|
a9f6afffc2 | ||
|
|
09f7f64099 | ||
|
|
4ab06abefe | ||
|
|
ce15fd21ad | ||
|
|
3c1399b44a | ||
|
|
50ca75da0e | ||
|
|
5b417a321a | ||
|
|
bbb43de87b | ||
|
|
2e4d306d79 | ||
|
|
afb7f4bd2e | ||
|
|
67db8b5be8 | ||
|
|
09d6556abd | ||
|
|
bfe4e01c85 | ||
|
|
d8304a3f00 | ||
|
|
8a443e9cad | ||
|
|
0e29639222 | ||
|
|
7b0725029f | ||
|
|
704d06cfe7 | ||
|
|
acfd7ebd2d | ||
|
|
5fb5693792 | ||
|
|
dd3f3f0499 | ||
|
|
ff73ed2521 | ||
|
|
5efa1d1795 | ||
|
|
f010365151 | ||
|
|
7f177f6b83 | ||
|
|
66b839742a | ||
|
|
2e2b0074b1 | ||
|
|
49283daa4f | ||
|
|
3bcda37e66 | ||
|
|
684cf30d2f | ||
|
|
8989478af4 | ||
|
|
d3446b64a3 | ||
|
|
87cd91b0f8 | ||
|
|
e01946a1e4 | ||
|
|
72edb1897f | ||
|
|
1c13343e8a | ||
|
|
85ee0747d1 | ||
|
|
e2f03aaf81 | ||
|
|
6c676fa8da | ||
|
|
183b3ae8cc | ||
|
|
43143bfdf6 | ||
|
|
c6a564f7e4 | ||
|
|
762aed50b7 | ||
|
|
bb91350ef5 | ||
|
|
ec9b299b37 | ||
|
|
0e6a4818ea | ||
|
|
181c984b27 | ||
|
|
7adbe01723 | ||
|
|
a5339af0dd | ||
|
|
c91e5e6b7b | ||
|
|
ccc4202aa4 | ||
|
|
118f848308 | ||
|
|
c36ff60778 | ||
|
|
474e610c3d | ||
|
|
0b6ae0ce32 | ||
|
|
fad1b984bf | ||
|
|
6cc6986904 | ||
|
|
26d5c0a08a | ||
|
|
78e1d1f81a | ||
|
|
48862141dc | ||
|
|
47f8264c31 | ||
|
|
851da0707c | ||
|
|
4275bdd0c0 | ||
|
|
828e5d0903 | ||
|
|
1cbd98ec53 | ||
|
|
df036d3904 | ||
|
|
08dbe94679 | ||
|
|
24e9764fcb | ||
|
|
eb2a2717b1 | ||
|
|
9d74fe2d6e | ||
|
|
8413f6345c | ||
|
|
37a53b747c | ||
|
|
a642080b90 | ||
|
|
9cb5cffdb1 | ||
|
|
57b9942cce | ||
|
|
1274584497 |
Executable
+12
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
if [ "$SKIP_SIMPLE_GIT_HOOKS" = "1" ]; then
|
||||||
|
echo "[INFO] SKIP_SIMPLE_GIT_HOOKS is set to 1, skipping hook."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$SIMPLE_GIT_HOOKS_RC" ]; then
|
||||||
|
. "$SIMPLE_GIT_HOOKS_RC"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# cd packages/web && bun run lint && bun run format
|
||||||
@@ -95,7 +95,7 @@ body:
|
|||||||
- type: input
|
- type: input
|
||||||
id: browser
|
id: browser
|
||||||
attributes:
|
attributes:
|
||||||
label: Browser
|
label: Browser
|
||||||
description: What browser are you using? Include version if possible.
|
description: What browser are you using? Include version if possible.
|
||||||
placeholder: e.g., Chrome 108, Firefox 107, Safari 16.2
|
placeholder: e.g., Chrome 108, Firefox 107, Safari 16.2
|
||||||
validations:
|
validations:
|
||||||
@@ -153,4 +153,4 @@ body:
|
|||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Thank you for helping improve our project by reporting this bug!
|
Thank you for helping improve our project by reporting this bug!
|
||||||
|
|||||||
@@ -62,4 +62,4 @@ body:
|
|||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Thank you for taking the time to fill out this feature request!
|
Thank you for taking the time to fill out this feature request!
|
||||||
|
|||||||
@@ -1,48 +1,50 @@
|
|||||||
<!--
|
<!--
|
||||||
Thank you for your contribution to our project! Please fill out the following template to help reviewers understand your changes.
|
Thank you for your contribution to our project!
|
||||||
-->
|
-->
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Provide a clear and concise description of what this PR does. Explain the problem it solves or the feature it adds.
|
Provide a clear and concise description of what this PR does. Explain the problem it solves or the feature it adds.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
## Related Issues
|
## Related Issues
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Link any related issues here using the GitHub syntax: "Fixes #123" or "Relates to #456".
|
Link any related issues here using the GitHub syntax: "Fixes #123" or "Relates to #456".
|
||||||
If there are no related issues, you can remove this section.
|
If there are no related issues, you can remove this section.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
## Changes Made
|
## Changes Made
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
List the key changes you've made. Focus on the most important aspects that reviewers should understand.
|
List the key changes you've made. Focus on the most important aspects that reviewers should understand.
|
||||||
-->
|
-->
|
||||||
-
|
|
||||||
-
|
-
|
||||||
-
|
-
|
||||||
-
|
-
|
||||||
|
|
||||||
## Testing Done
|
## Testing Done
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Describe how you tested these changes.
|
Describe how you tested these changes (added new tests, etc).
|
||||||
-->
|
-->
|
||||||
|
|
||||||
## Screenshots (if applicable)
|
## Screenshots (if applicable)
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
If your changes affect the UI, include screenshots or screencasts showing the before and after.
|
If your changes affect the UI, include screenshots or screencasts showing the before and after.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
## Checklist
|
## Checklist
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Check all that apply. If an item doesn't apply to your PR, you can leave it unchecked or remove it.
|
Check all that apply. If an item doesn't apply to your PR, you can leave it unchecked or remove it.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
- [ ] Code follows project style guidelines
|
- [ ] Code follows project style guidelines
|
||||||
- [ ] Documentation has been updated or added
|
- [ ] Documentation has been updated or added
|
||||||
- [ ] Tests have been added or updated
|
- [ ] Tests have been added or updated
|
||||||
- [ ] All CI checks pass
|
- [ ] All i18n translation labels have been added (read
|
||||||
- [ ] Dependent changes have been merged
|
CONTRIBUTING_I18N_DEVELOPER_GUIDE.md for more details)
|
||||||
|
|
||||||
## Additional Notes
|
|
||||||
<!--
|
|
||||||
Add any other context about the PR here.
|
|
||||||
-->
|
|
||||||
|
|||||||
+54
-26
@@ -1,10 +1,9 @@
|
|||||||
name: Push to Master/Main CI
|
name: Push to Main CI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- master
|
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
@@ -17,35 +16,64 @@ jobs:
|
|||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Deno
|
- name: Setup pnpm
|
||||||
uses: denoland/setup-deno@v2
|
uses: pnpm/action-setup@v4
|
||||||
with:
|
with:
|
||||||
deno-version: v2.x
|
version: latest
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Setup Node.js
|
||||||
run: deno install
|
uses: actions/setup-node@v4
|
||||||
|
|
||||||
- name: Cache Deno dependencies
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
with:
|
||||||
path: |
|
node-version: 22
|
||||||
~/.cache/deno
|
cache: pnpm
|
||||||
./deno.lock
|
cache-dependency-path: '**/pnpm-lock.yaml'
|
||||||
key: ${{ runner.os }}-deno-${{ hashFiles('**/deno.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-deno-
|
|
||||||
|
|
||||||
- name: Cache Dependencies
|
- name: Prewarm & Install (workspace)
|
||||||
run: deno cache src/index.tsx
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
pnpm fetch
|
||||||
|
pnpm install --frozen-lockfile --offline
|
||||||
|
|
||||||
- name: Run linter
|
- name: Build All Packages (with exclusions)
|
||||||
run: deno task lint
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
- name: Check formatter
|
# List packages to exclude (full paths under repo root)
|
||||||
run: deno task format --check
|
EXCLUDED_DIRS=("packages/protobufs" "packages/transport-deno")
|
||||||
|
|
||||||
- name: Run tests
|
is_excluded() {
|
||||||
run: deno task test
|
local dir="$1"
|
||||||
|
for ex in "${EXCLUDED_DIRS[@]}"; do
|
||||||
|
if [[ "$dir" == "$ex" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
- name: Build Package
|
for pkg_dir in packages/*/; do
|
||||||
run: deno task build
|
pkg_dir="${pkg_dir%/}" # trim trailing slash
|
||||||
|
|
||||||
|
# Must be a directory with a package.json
|
||||||
|
if [[ ! -f "$pkg_dir/package.json" ]]; then
|
||||||
|
echo "⚠️ Skipping $pkg_dir (no package.json)"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Allow for exclusions
|
||||||
|
if is_excluded "$pkg_dir"; then
|
||||||
|
echo "🚫 Skipping $pkg_dir (excluded)"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optionally skip Deno-first packages automatically
|
||||||
|
if [[ -f "$pkg_dir/deno.json" || -f "$pkg_dir/deno.jsonc" ]]; then
|
||||||
|
echo "🦕 Skipping $pkg_dir (deno project)"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "🔧 Building: $pkg_dir"
|
||||||
|
# No per-package install needed; workspace install already done
|
||||||
|
pnpm -C "$pkg_dir" run build:npm
|
||||||
|
done
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
name: Crowdin Download Translations Action
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule: # Every Sunday at midnight
|
||||||
|
- cron: "0 0 * * 0"
|
||||||
|
workflow_dispatch: # Allow manual triggering
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
synchronize-with-crowdin:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Download translations with Crowdin
|
||||||
|
uses: crowdin/github-action@v2
|
||||||
|
with:
|
||||||
|
base_url: "https://meshtastic.crowdin.com/api/v2"
|
||||||
|
config: "./packages/web/crowdin.yml"
|
||||||
|
upload_sources: false
|
||||||
|
upload_translations: false
|
||||||
|
download_translations: true
|
||||||
|
localization_branch_name: i18n_crowdin_translations
|
||||||
|
commit_message: "chore(i18n): New Crowdin Translations by GitHub Action"
|
||||||
|
create_pull_request: true
|
||||||
|
pull_request_title: "chore(i18n): New Crowdin Translations"
|
||||||
|
pull_request_body: "New Crowdin translations by [Crowdin GH Action](https://github.com/crowdin/github-action)"
|
||||||
|
pull_request_base_branch_name: "main"
|
||||||
|
pull_request_labels: "i18n"
|
||||||
|
crowdin_branch_name: "main"
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
|
||||||
|
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
name: Crowdin Upload Sources Action
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
# Monitor all .json files within the /i18n/locales/en/ directory.
|
||||||
|
# This ensures the workflow triggers if any the English namespace files are modified on the main branch.
|
||||||
|
paths:
|
||||||
|
- "/packages/web/public/i18n/locales/en/*.json"
|
||||||
|
branches: [main]
|
||||||
|
workflow_dispatch: # Allow manual triggering
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
synchronize-with-crowdin:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Upload sources with Crowdin
|
||||||
|
uses: crowdin/github-action@v2
|
||||||
|
with:
|
||||||
|
base_url: "https://meshtastic.crowdin.com/api/v2"
|
||||||
|
config: "./packages/web/crowdin.yml"
|
||||||
|
upload_sources: true
|
||||||
|
upload_translations: false
|
||||||
|
download_translations: false
|
||||||
|
crowdin_branch_name: "main"
|
||||||
|
|
||||||
|
env:
|
||||||
|
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
|
||||||
|
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
name: Crowdin Upload Translations Action
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: # Allow manual triggering
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
synchronize-with-crowdin:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Upload translations with Crowdin
|
||||||
|
uses: crowdin/github-action@v2
|
||||||
|
with:
|
||||||
|
base_url: "https://meshtastic.crowdin.com/api/v2"
|
||||||
|
config: "./packages/web/crowdin.yml"
|
||||||
|
upload_sources: false
|
||||||
|
upload_translations: true
|
||||||
|
download_translations: false
|
||||||
|
crowdin_branch_name: "main"
|
||||||
|
env:
|
||||||
|
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
|
||||||
|
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||||
@@ -1,66 +1,120 @@
|
|||||||
name: 'Nightly Release'
|
name: Nightly Release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "0 5 * * *" # Run every day at 5am UTC
|
- cron: "0 5 * * *" # 05:00 UTC daily
|
||||||
|
workflow_dispatch: {} # allow manual runs too
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: read
|
||||||
packages: write
|
packages: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY_IMAGE: ghcr.io/${{ github.repository }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-package:
|
nightly-build-and-push:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Deno
|
|
||||||
uses: denoland/setup-deno@v2
|
|
||||||
with:
|
|
||||||
deno-version: v2.x
|
|
||||||
|
|
||||||
- name: Install Dependencies
|
|
||||||
run: deno install
|
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 22
|
||||||
|
cache: pnpm
|
||||||
|
cache-dependency-path: '**/pnpm-lock.yaml'
|
||||||
|
|
||||||
|
- name: Install dependencies (root)
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: deno task test
|
run: pnpm run test
|
||||||
|
|
||||||
- name: Build Package
|
- name: Build web package
|
||||||
run: deno task build
|
working-directory: packages/web
|
||||||
|
run: pnpm run build
|
||||||
|
|
||||||
- name: Package Output
|
- name: Package output
|
||||||
run: deno task package
|
working-directory: packages/web
|
||||||
|
run: pnpm run package
|
||||||
|
|
||||||
- name: Archive compressed build
|
- name: Upload compressed build (artifact)
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build
|
name: web-build-nightly
|
||||||
path: dist/build.tar
|
path: packages/web/dist/build.tar
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
- name: Compute tags and labels
|
||||||
|
id: meta
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
DATE="$(date -u +%Y%m%d)"
|
||||||
|
ISO_CREATED="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||||
|
SHORTSHA="$(git rev-parse --short=12 HEAD)"
|
||||||
|
|
||||||
|
# Try to use latest release tag if it exists; fallback to package version; else date
|
||||||
|
LATEST_TAG="$(gh release view --json tagName --jq .tagName 2>/dev/null || true)"
|
||||||
|
if [ -z "$LATEST_TAG" ] && [ -f packages/web/package.json ]; then
|
||||||
|
LATEST_TAG="v$(jq -r .version packages/web/package.json)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "${LATEST_TAG:-}" ] && [ "$LATEST_TAG" != "vnull" ]; then
|
||||||
|
IMMUTABLE="nightly-${LATEST_TAG}-${SHORTSHA}"
|
||||||
|
else
|
||||||
|
IMMUTABLE="nightly-${DATE}-${SHORTSHA}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Outputs
|
||||||
|
echo "moving_tag=nightly" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "immutable_tag=${IMMUTABLE}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "all_tags=nightly ${IMMUTABLE}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "created=${ISO_CREATED}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Resolved tags: nightly and ${IMMUTABLE}"
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
- name: Buildah Build
|
- name: Build Container Image (multi-arch)
|
||||||
id: build-container
|
id: build-container
|
||||||
uses: redhat-actions/buildah-build@v2
|
uses: redhat-actions/buildah-build@v2
|
||||||
with:
|
with:
|
||||||
containerfiles: |
|
containerfiles: |
|
||||||
./infra/Containerfile
|
./packages/web/infra/Containerfile
|
||||||
image: ${{github.event.repository.full_name}}
|
image: ${{ env.REGISTRY_IMAGE }}
|
||||||
tags: nightly ${{ github.sha }}
|
tags: |
|
||||||
|
${{ steps.meta.outputs.moving_tag }}
|
||||||
|
${{ steps.meta.outputs.immutable_tag }}
|
||||||
oci: true
|
oci: true
|
||||||
platforms: linux/amd64, linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
|
labels: |
|
||||||
|
org.opencontainers.image.source=${{ github.repository }}
|
||||||
|
org.opencontainers.image.revision=${{ github.sha }}
|
||||||
|
org.opencontainers.image.created=${{ steps.meta.outputs.created }}
|
||||||
|
|
||||||
- name: Push To Registry
|
- name: Push To GHCR
|
||||||
id: push-to-registry
|
id: push-to-registry
|
||||||
uses: redhat-actions/push-to-registry@v2
|
uses: redhat-actions/push-to-registry@v2
|
||||||
with:
|
with:
|
||||||
image: ${{ steps.build-container.outputs.image }}
|
image: ${{ steps.build-container.outputs.image }}
|
||||||
tags: ${{ steps.build-container.outputs.tags }}
|
# Push the same tags used at build time:
|
||||||
|
tags: ${{ steps.meta.outputs.all_tags }}
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Print image url
|
- name: Print image URLs
|
||||||
run: echo "Image pushed to ${{ steps.push-to-registry.outputs.registry-paths }}"
|
run: |
|
||||||
|
echo "Moving tag: ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.moving_tag }}"
|
||||||
|
echo "Immutable tag: ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.immutable_tag }}"
|
||||||
|
|||||||
+33
-34
@@ -2,52 +2,51 @@ name: Pull Request CI
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened, ready_for_review]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: pr-${{ github.event.pull_request.number }}-ci
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
CI: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build-and-package:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
# Skip for draft PRs; remove this line if you want to run on drafts too
|
||||||
|
if: ${{ github.event.pull_request.draft == false }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Deno
|
|
||||||
uses: denoland/setup-deno@v2
|
|
||||||
with:
|
|
||||||
deno-version: v2.x
|
|
||||||
|
|
||||||
- name: Cache Deno dependencies
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.cache/deno
|
|
||||||
./deno.lock
|
|
||||||
key: ${{ runner.os }}-deno-${{ hashFiles('**/deno.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-deno-
|
|
||||||
|
|
||||||
- name: Install Dependencies
|
- name: Setup pnpm
|
||||||
run: deno install
|
uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
|
||||||
- name: Cache Dependencies
|
- name: Setup Node.js
|
||||||
run: deno cache src/index.tsx
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 22
|
||||||
|
cache: pnpm
|
||||||
|
cache-dependency-path: '**/pnpm-lock.yaml'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: Run linter
|
- name: Run linter
|
||||||
run: deno task lint
|
run: pnpm run lint
|
||||||
|
|
||||||
- name: Check formatter
|
- name: Check formatter
|
||||||
run: deno task format --check
|
run: pnpm run check
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: deno task test
|
run: pnpm run test
|
||||||
|
|
||||||
- name: Build Package
|
- name: Build web package
|
||||||
run: deno task build
|
run: pnpm --filter "./packages/web" run build
|
||||||
|
|
||||||
- name: Compress build
|
|
||||||
run: deno task package
|
|
||||||
|
|
||||||
- name: Archive compressed build
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: build
|
|
||||||
path: dist/build.tar
|
|
||||||
|
|||||||
@@ -0,0 +1,148 @@
|
|||||||
|
name: Release Packages
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
packages:
|
||||||
|
description: 'Packages to release (comma-separated, or "all")'
|
||||||
|
required: false
|
||||||
|
default: 'all'
|
||||||
|
bump:
|
||||||
|
description: 'Semver bump (patch | minor | major)'
|
||||||
|
required: false
|
||||||
|
default: 'patch'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write # we commit the bumped versions back
|
||||||
|
id-token: write # required for JSR OIDC
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 22
|
||||||
|
cache: pnpm
|
||||||
|
cache-dependency-path: '**/pnpm-lock.yaml'
|
||||||
|
registry-url: 'https://registry.npmjs.org'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Resolve package list
|
||||||
|
id: pkgs
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
if [ "${{ github.event.inputs.packages }}" = "all" ] || [ -z "${{ github.event.inputs.packages }}" ]; then
|
||||||
|
mapfile -t TARGETS < <(ls -d packages/* | grep -v 'packages/web')
|
||||||
|
else
|
||||||
|
IFS=',' read -ra TARGETS <<< "${{ github.event.inputs.packages }}"
|
||||||
|
TARGETS=("${TARGETS[@]/#/packages/}")
|
||||||
|
fi
|
||||||
|
printf '%s\n' "${TARGETS[@]}" | paste -sd, - > targets.txt
|
||||||
|
echo "list=$(cat targets.txt)" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Targets: $(cat targets.txt)"
|
||||||
|
|
||||||
|
- name: Bump package.json versions (no git tag)
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
BUMP="${{ github.event.inputs.bump }}"
|
||||||
|
IFS=',' read -ra TARGETS <<< "${{ steps.pkgs.outputs.list }}"
|
||||||
|
for dir in "${TARGETS[@]}"; do
|
||||||
|
if [ -f "$dir/package.json" ]; then
|
||||||
|
echo "Bumping $dir -> $BUMP"
|
||||||
|
(cd "$dir" && npm version "$BUMP" --no-git-tag-version --allow-same-version)
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Generate jsr.json from package.json (pkg-to-jsr)
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=',' read -ra TARGETS <<< "${{ steps.pkgs.outputs.list }}"
|
||||||
|
for dir in "${TARGETS[@]}"; do
|
||||||
|
if [ -f "$dir/package.json" ]; then
|
||||||
|
echo "Generating jsr.json for $dir"
|
||||||
|
pnpm dlx pkg-to-jsr --root "$dir"
|
||||||
|
# # Optional: show result
|
||||||
|
# jq -C . "$dir/jsr.json" || cat "$dir/jsr.json"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
- name: Commit version bumps
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
git add packages/*/package.json packages/*/jsr.json 2>/dev/null || true
|
||||||
|
if ! git diff --cached --quiet; then
|
||||||
|
git checkout -b version_bump
|
||||||
|
git commit -m "chore(release): bump package versions (${{ github.event.inputs.bump }})"
|
||||||
|
git push -u origin version_bump
|
||||||
|
gh pr create --title "Bump package versions" --body "Bump versions of NPM and JSR packages" --base main --head version_bump
|
||||||
|
echo "Pushed to branch version_bump"
|
||||||
|
else
|
||||||
|
echo "No changes to commit."
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Build selected packages
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=',' read -ra TARGETS <<< "${{ steps.pkgs.outputs.list }}"
|
||||||
|
for dir in "${TARGETS[@]}"; do
|
||||||
|
echo "Building $dir"
|
||||||
|
pnpm --filter "./$dir" run build
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Publish to JSR (OIDC)
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=',' read -ra TARGETS <<< "${{ steps.pkgs.outputs.list }}"
|
||||||
|
for dir in "${TARGETS[@]}"; do
|
||||||
|
if [ -f "$dir/jsr.json" ]; then
|
||||||
|
echo "Publishing $dir to JSR via OIDC…"
|
||||||
|
( cd "$dir"
|
||||||
|
[ -d dist ] || pnpm run build
|
||||||
|
npx --yes jsr publish
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Configure npm auth
|
||||||
|
run: |
|
||||||
|
pnpm config set //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}
|
||||||
|
pnpm config set registry https://registry.npmjs.org/
|
||||||
|
|
||||||
|
- name: Publish to npm
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=',' read -ra TARGETS <<< "${{ steps.pkgs.outputs.list }}"
|
||||||
|
for dir in "${TARGETS[@]}"; do
|
||||||
|
if [ -f "$dir/package.json" ]; then
|
||||||
|
echo "Publishing $dir to npm…"
|
||||||
|
( cd "$dir"
|
||||||
|
[ -d dist ] || pnpm run build
|
||||||
|
npm publish --access public
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
done
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
env:
|
||||||
|
PROTOBUF_DIR: ./packages/protobufs
|
||||||
|
|
||||||
|
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 $PROTOBUF_DIR/packages/ts || true
|
||||||
|
cat $PROTOBUF_DIR/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: ${{ env.PROTOBUF_DIR }}/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: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
|
||||||
|
- name: Install workspace dependencies
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Generate code
|
||||||
|
run: pnpm --filter @meshtastic/protobufs-ws build
|
||||||
|
|
||||||
|
- name: Move generated .ts files and clean up
|
||||||
|
run: |
|
||||||
|
set -euxo pipefail
|
||||||
|
SRC_DIR="$PROTOBUF_DIR/packages/ts/dist/meshtastic"
|
||||||
|
DEST_DIR="$PROTOBUF_DIR/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 $PROTOBUF_DIR/packages/ts
|
||||||
|
cp README.md $PROTOBUF_DIR/packages/ts
|
||||||
|
|
||||||
|
- name: Upload TypeScript code
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ts_code
|
||||||
|
path: ${{ env.PROTOBUF_DIR }}/packages/ts
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
name: Release Web
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [released, prereleased]
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
ref:
|
||||||
|
description: "Git ref (branch, tag, or SHA) to build"
|
||||||
|
required: false
|
||||||
|
default: ""
|
||||||
|
tag_name:
|
||||||
|
description: "Tag to use for artifacts/images (defaults to <sha>)"
|
||||||
|
required: false
|
||||||
|
default: ""
|
||||||
|
attach_to_release:
|
||||||
|
description: "Upload build.tar to an existing GitHub Release (requires tag_name)"
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY_IMAGE: ghcr.io/${{ github.repository }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release-web:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ inputs.ref != '' && inputs.ref || github.ref }}
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 22
|
||||||
|
cache: pnpm
|
||||||
|
cache-dependency-path: '**/pnpm-lock.yaml'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Build web package
|
||||||
|
working-directory: packages/web
|
||||||
|
run: pnpm run build
|
||||||
|
|
||||||
|
- name: Create release archive
|
||||||
|
working-directory: packages/web
|
||||||
|
run: pnpm run package
|
||||||
|
|
||||||
|
- name: Upload archive (artifact)
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: web-build
|
||||||
|
path: packages/web/dist/build.tar
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
- name: Attach archive to GitHub Release
|
||||||
|
if: ${{ github.event_name == 'release' || inputs.attach_to_release == true }}
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
files: packages/web/dist/build.tar
|
||||||
|
tag_name: ${{ github.event_name == 'release' && github.event.release.tag_name || inputs.tag_name }}
|
||||||
|
fail_on_unmatched_files: true
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
# Compute created timestamp & short SHA for labels/tags
|
||||||
|
- name: Compute meta
|
||||||
|
id: gen
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "created=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "shortsha=$(git rev-parse --short=12 HEAD)" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
# Build/tag matrix:
|
||||||
|
# - For release events: vX.Y.Z, semver helpers, and latest (only if NOT prerelease)
|
||||||
|
# - For prerelease events: vX.Y.Z and semver helpers (NO latest)
|
||||||
|
# - For manual runs:
|
||||||
|
# * if tag_name set: that raw tag
|
||||||
|
# * else: adhoc-<shortsha>
|
||||||
|
- name: Docker metadata (tags & labels)
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v5
|
||||||
|
with:
|
||||||
|
images: ${{ env.REGISTRY_IMAGE }}
|
||||||
|
labels: |
|
||||||
|
org.opencontainers.image.source=${{ github.repository }}
|
||||||
|
org.opencontainers.image.revision=${{ github.sha }}
|
||||||
|
org.opencontainers.image.created=${{ steps.gen.outputs.created }}
|
||||||
|
tags: |
|
||||||
|
# Full release (semantic tag)
|
||||||
|
type=raw,value=${{ github.event.release.tag_name }},enable=${{ github.event_name == 'release' }}
|
||||||
|
# Semver helpers (major, major.minor) for releases/prereleases
|
||||||
|
type=semver,pattern={{version}},value=${{ github.event.release.tag_name }},enable=${{ github.event_name == 'release' }}
|
||||||
|
type=semver,pattern={{major}}.{{minor}},value=${{ github.event.release.tag_name }},enable=${{ github.event_name == 'release' && github.event.release.prerelease == false }}
|
||||||
|
type=semver,pattern={{major}},value=${{ github.event.release.tag_name }},enable=${{ github.event_name == 'release' && github.event.release.prerelease == false }}
|
||||||
|
# Latest only for full releases (not prereleases)
|
||||||
|
type=raw,value=latest,enable=${{ github.event_name == 'release' && github.event.release.prerelease == false }}
|
||||||
|
# Manual: provided tag_name
|
||||||
|
type=raw,value=${{ inputs.tag_name }},enable=${{ github.event_name == 'workflow_dispatch' && inputs.tag_name != '' }}
|
||||||
|
# Manual: fallback to adhoc-<shortsha>
|
||||||
|
type=raw,value=adhoc-${{ steps.gen.outputs.shortsha }},enable=${{ github.event_name == 'workflow_dispatch' && inputs.tag_name == '' }}
|
||||||
|
# Always add immutable sha tag for traceability
|
||||||
|
type=raw,value=sha-${{ steps.gen.outputs.shortsha }}
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
|
- name: Set up Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Login to GHCR
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
# Push images for:
|
||||||
|
# - release (released or prereleased)
|
||||||
|
# - manual with a tag_name (adhoc builds can still be pushed by name)
|
||||||
|
- name: Build and push image
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./packages/web/infra/Containerfile
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.tag_name != '') }}
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
provenance: false
|
||||||
|
|
||||||
|
- name: Output image refs
|
||||||
|
if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.tag_name != '') }}
|
||||||
|
run: |
|
||||||
|
echo "🖼️ Pushed tags:"
|
||||||
|
echo "${{ steps.meta.outputs.tags }}"
|
||||||
|
echo
|
||||||
|
echo "Pull examples:"
|
||||||
|
if [[ "${{ github.event_name }}" == "release" && "${{ github.event.release.prerelease }}" == "false" ]]; then
|
||||||
|
echo " docker pull ${{ env.REGISTRY_IMAGE }}:latest"
|
||||||
|
fi
|
||||||
|
# Always available:
|
||||||
|
echo " docker pull ${{ env.REGISTRY_IMAGE }}:${{ github.event.release.tag_name || inputs.tag_name || format('adhoc-{0}', steps.gen.outputs.shortsha) }}"
|
||||||
|
echo " docker pull ${{ env.REGISTRY_IMAGE }}:sha-${{ steps.gen.outputs.shortsha }}"
|
||||||
|
|
||||||
|
- name: Explain no image push
|
||||||
|
if: ${{ !(github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.tag_name != '')) }}
|
||||||
|
run: echo "ℹ️ No image pushed (manual run without tag_name)."
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
name: Release
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [released, prereleased]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
packages: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-and-package:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup Deno
|
|
||||||
uses: denoland/setup-deno@v2
|
|
||||||
with:
|
|
||||||
deno-version: v2.x
|
|
||||||
|
|
||||||
- name: Install Dependencies
|
|
||||||
run: deno install
|
|
||||||
|
|
||||||
- name: Run tests
|
|
||||||
run: deno task test
|
|
||||||
|
|
||||||
- name: Build Package
|
|
||||||
run: deno task build
|
|
||||||
|
|
||||||
- name: Package Output
|
|
||||||
run: deno task package
|
|
||||||
|
|
||||||
- name: Archive compressed build
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: build
|
|
||||||
path: dist/build.tar
|
|
||||||
|
|
||||||
- name: Attach build.tar to release
|
|
||||||
run: |
|
|
||||||
gh release upload ${{ github.event.release.tag_name }} dist/build.tar
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
|
|
||||||
- name: Buildah Build
|
|
||||||
id: build-container
|
|
||||||
uses: redhat-actions/buildah-build@v2
|
|
||||||
with:
|
|
||||||
containerfiles: |
|
|
||||||
./infra/Containerfile
|
|
||||||
image: ${{github.event.repository.full_name}}
|
|
||||||
tags: latest ${{ github.sha }}
|
|
||||||
oci: true
|
|
||||||
platforms: linux/amd64, linux/arm64
|
|
||||||
|
|
||||||
- name: Push To Registry
|
|
||||||
id: push-to-registry
|
|
||||||
uses: redhat-actions/push-to-registry@v2
|
|
||||||
with:
|
|
||||||
image: ${{ steps.build-container.outputs.image }}
|
|
||||||
tags: ${{ steps.build-container.outputs.tags }}
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Print image url
|
|
||||||
run: echo "Image pushed to ${{ steps.push-to-registry.outputs.registry-paths }}"
|
|
||||||
@@ -1,50 +1,73 @@
|
|||||||
name: Update Stable Branch from Master on Latest Release
|
name: Update Stable Branch from Main on Latest Release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [released]
|
types: [released]
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: update-stable-${{ github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update-stable-branch:
|
update-stable-branch:
|
||||||
name: Update Stable Branch from Master
|
name: Update stable from latest release source
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0 # need full history for reset/push
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Configure Git
|
- name: Configure Git author
|
||||||
run: |
|
run: |
|
||||||
git config user.name "GitHub Actions Bot"
|
git config user.name "github-actions[bot]"
|
||||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
|
||||||
- name: Fetch latest master and stable branches
|
- name: Determine source ref & SHA
|
||||||
|
id: meta
|
||||||
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
git fetch origin master:master
|
set -euo pipefail
|
||||||
git fetch origin stable:stable || echo "Stable branch not found remotely, will create."
|
SRC="${{ github.event.release.target_commitish }}"
|
||||||
|
if [ -z "$SRC" ] || ! git ls-remote --exit-code origin "refs/heads/$SRC" >/dev/null 2>&1; then
|
||||||
- name: Get latest master commit SHA
|
# Fallback to main if target_commitish is empty or not a branch
|
||||||
id: get_master_sha
|
SRC="main"
|
||||||
run: echo "MASTER_SHA=$(git rev-parse master)" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Check out stable branch
|
|
||||||
run: |
|
|
||||||
if git show-ref --verify --quiet refs/heads/stable; then
|
|
||||||
git checkout stable
|
|
||||||
git pull origin stable # Sync with remote stable if it exists
|
|
||||||
else
|
|
||||||
echo "Creating local stable branch based on master HEAD."
|
|
||||||
git checkout -b stable ${{ env.MASTER_SHA }}
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Reset stable branch to latest master
|
echo "Using source branch: $SRC"
|
||||||
run: git reset --hard ${{ env.MASTER_SHA }}
|
git fetch origin "$SRC":"refs/remotes/origin/$SRC" --prune
|
||||||
|
SHA="$(git rev-parse "origin/$SRC")"
|
||||||
|
echo "sha=$SHA" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "src=$SRC" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Force push stable branch
|
- name: Prepare local stable branch
|
||||||
run: git push origin stable --force
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
# Ensure we have the remote stable ref if it exists
|
||||||
|
git fetch origin stable:refs/remotes/origin/stable || true
|
||||||
|
|
||||||
|
if git show-ref --verify --quiet refs/heads/stable; then
|
||||||
|
echo "Local stable exists."
|
||||||
|
elif git show-ref --verify --quiet refs/remotes/origin/stable; then
|
||||||
|
echo "Creating local stable tracking branch from remote."
|
||||||
|
git checkout -b stable --track origin/stable
|
||||||
|
else
|
||||||
|
echo "Creating new local stable branch at source SHA."
|
||||||
|
git checkout -b stable "${{ steps.meta.outputs.sha }}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Reset stable to source SHA
|
||||||
|
run: |
|
||||||
|
git checkout stable
|
||||||
|
git reset --hard "${{ steps.meta.outputs.sha }}"
|
||||||
|
git status --short --branch
|
||||||
|
|
||||||
|
- name: Push stable (force-with-lease)
|
||||||
|
run: |
|
||||||
|
# Safer than --force; refuses if remote moved unexpectedly
|
||||||
|
git push origin stable --force-with-lease
|
||||||
|
|||||||
+8
-2
@@ -1,7 +1,13 @@
|
|||||||
dist
|
|
||||||
node_modules
|
node_modules
|
||||||
|
dist
|
||||||
stats.html
|
stats.html
|
||||||
.vercel
|
.vercel
|
||||||
.vite
|
.vite
|
||||||
dev-dist
|
dev-dist
|
||||||
__screenshots__*
|
__screenshots__*
|
||||||
|
*.diff
|
||||||
|
npm/
|
||||||
|
.idea
|
||||||
|
**/LICENSE
|
||||||
|
|
||||||
|
packages/protobufs/packages/ts/dist
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "packages/packages/protobufs"]
|
||||||
|
path = packages/packages/protobufs
|
||||||
|
url = https://github.com/meshtastic/protobufs
|
||||||
Vendored
+7
-3
@@ -1,6 +1,10 @@
|
|||||||
{
|
{
|
||||||
"deno.enable": true,
|
|
||||||
"deno.suggest.imports.autoDiscover": true,
|
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
"editor.defaultFormatter": "denoland.vscode-deno"
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll.biome": "explicit"
|
||||||
|
},
|
||||||
|
"search.exclude": {
|
||||||
|
"**/i18n/locales/*-*/**": true
|
||||||
|
},
|
||||||
|
"vitest.workspaceConfig": "vitest.config.ts"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,153 +1,92 @@
|
|||||||
# Meshtastic Web
|
# Meshtastic Web Monorepo
|
||||||
|
|
||||||
<!--Project specific badges here-->
|
[](https://github.com/meshtastic/web/actions/workflows/ci.yml)
|
||||||
|
[](https://github.com/meshtastic/js/actions/workflows/ci.yml)
|
||||||
[](https://github.com/meshtastic/web/actions/workflows/ci.yml)
|
|
||||||
[](https://cla-assistant.io/meshtastic/web)
|
[](https://cla-assistant.io/meshtastic/web)
|
||||||
[](https://opencollective.com/meshtastic/)
|
[](https://opencollective.com/meshtastic/)
|
||||||
[](https://vercel.com?utm_source=meshtastic&utm_campaign=oss)
|
[](https://vercel.com?utm_source=meshtastic&utm_campaign=oss)
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Official [Meshtastic](https://meshtastic.org) web interface, that can be hosted
|
This monorepo consolidates the official [Meshtastic](https://meshtastic.org) web
|
||||||
or served from a node
|
interface and its supporting JavaScript libraries. It aims to provide a unified
|
||||||
|
development experience for interacting with Meshtastic devices.
|
||||||
|
|
||||||
**[Hosted version](https://client.meshtastic.org)**
|
### Projects within this Monorepo (`packages/`)
|
||||||
|
|
||||||
|
All projects are located within the `packages/` directory:
|
||||||
|
|
||||||
|
- **`packages/web` (Meshtastic Web Client):** The official web interface,
|
||||||
|
designed to be hosted or served directly from a Meshtastic node.
|
||||||
|
- **[Hosted version](https://client.meshtastic.org)**
|
||||||
|
- **`packages/core`:** Core functionality for Meshtastic JS.
|
||||||
|
- **`packages/transport-node`:** TCP Transport for the NodeJS runtime.
|
||||||
|
- **`packages/transport-node-serial`:** NodeJS Serial Transport for the NodeJS runtime.
|
||||||
|
- **`packages/transport-deno`:** TCP Transport for the Deno runtime.
|
||||||
|
- **`packages/transport-http`:** HTTP Transport.
|
||||||
|
- **`packages/transport-web-bluetooth`:** Web Bluetooth Transport.
|
||||||
|
- **`packages/transport-web-serial`:** Web Serial Transport.
|
||||||
|
- **`packages/protobufs`:** Git submodule containing Meshtastic’s shared protobuf definitions, used to generate and publish the JSR protobuf package.
|
||||||
|
|
||||||
|
All `Meshtastic JS` packages (core and transports) are published both to
|
||||||
|
[JSR](https://jsr.io/@meshtastic). [NPM](https://www.npmjs.com/org/meshtastic)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Stats
|
## Stats
|
||||||
|
|
||||||

|
| Project | Repobeats |
|
||||||
|
| :------------- | :-------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| Meshtastic Web |  |
|
||||||
|
|
||||||
## Progress Web App Support (PWA)
|
---
|
||||||
|
|
||||||
Meshtastic Web Client now includes Progressive Web App (PWA) functionality,
|
## Tech Stack
|
||||||
allowing users to:
|
|
||||||
|
|
||||||
- Install the app on desktop and mobile devices
|
This monorepo leverages the following technologies:
|
||||||
- Access the interface offline
|
|
||||||
- Receive updates automatically
|
|
||||||
- Experience faster load times with caching
|
|
||||||
|
|
||||||
To install as a PWA:
|
- **Runtime:** pnpm / Deno
|
||||||
|
- **Web Client:** React.js
|
||||||
|
- **Styling:** Tailwind CSS
|
||||||
|
- **Bundling:** Vite
|
||||||
|
- **Language:** TypeScript
|
||||||
|
- **Testing:** Vitest, React Testing Library
|
||||||
|
|
||||||
- On desktop: Look for the install icon in your browser's address bar
|
---
|
||||||
- On mobile: Use "Add to Home Screen" option in your browser menu
|
|
||||||
|
|
||||||
PWA functionality works with both the hosted version and self-hosted instances.
|
## Getting Started
|
||||||
|
|
||||||
## Self-host
|
### Prerequisites
|
||||||
|
|
||||||
The client can be self hosted using the precompiled container images with an OCI
|
You'll need to have [pnpm](https://pnpm.io/) installed to work with this monorepo.
|
||||||
compatible runtime such as [Docker](https://www.docker.com/) or
|
Follow the installation instructions on their home page.
|
||||||
[Podman](https://podman.io/). The base image used is
|
|
||||||
[Nginx 1.27](https://hub.docker.com/_/nginx)
|
|
||||||
|
|
||||||
```bash
|
### Development Setup
|
||||||
# With Docker
|
|
||||||
docker run -d -p 8080:8080 --restart always --name Meshtastic-Web ghcr.io/meshtastic/web
|
|
||||||
|
|
||||||
#With Podman
|
1. **Clone the repository:**
|
||||||
podman run -d -p 8080:8080 --restart always --name Meshtastic-Web ghcr.io/meshtastic/web
|
```bash
|
||||||
```
|
git clone https://github.com/meshtastic/meshtastic-web.git
|
||||||
|
cd meshtastic-web
|
||||||
|
```
|
||||||
|
2. **Install dependencies for all packages:**
|
||||||
|
```bash
|
||||||
|
pnpm install
|
||||||
|
```
|
||||||
|
This command installs all necessary dependencies for all packages within the
|
||||||
|
monorepo.
|
||||||
|
|
||||||
## Release Schedule
|
### Running Projects
|
||||||
|
|
||||||
Our release process follows these guidelines:
|
#### Meshtastic Web Client
|
||||||
|
|
||||||
- **Versioning:** We use Semantic Versioning (`Major.Minor.Patch`).
|
Please refer to the [Meshtastic Web README](packages/web/README.md) for setup and usage.
|
||||||
- **Stable Releases:** Published around the beginning of each month (e.g.,
|
|
||||||
`v2.3.4`).
|
|
||||||
- **Pre-releases:** A pre-release is typically issued mid-month for testing and
|
|
||||||
early adoption.
|
|
||||||
- **Nightly Builds:** An experimental Docker image containing the latest
|
|
||||||
cutting-edge features and fixes is automatically built nightly from the
|
|
||||||
`master` branch.
|
|
||||||
|
|
||||||
### Nightly Builds
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# With Docker
|
|
||||||
docker run -d -p 8080:8080 --restart always --name Meshtastic-Web ghcr.io/meshtastic/web:nightly
|
|
||||||
#With Podman
|
|
||||||
podman run -d -p 8080:8080 --restart always --name Meshtastic-Web ghcr.io/meshtastic/web:nightly
|
|
||||||
```
|
|
||||||
|
|
||||||
> [!WARNING]
|
|
||||||
>
|
|
||||||
> - Nightly builds represent the latest development state and may contain
|
|
||||||
> breaking changes
|
|
||||||
> - These builds undergo automated testing but may be less stable than tagged
|
|
||||||
> release versions
|
|
||||||
> - Not recommended for production environments unless you are actively testing
|
|
||||||
> new features
|
|
||||||
> - No guarantee of backward compatibility between nightly builds
|
|
||||||
|
|
||||||
#### Version Information
|
|
||||||
|
|
||||||
Each nightly build is tagged with:
|
|
||||||
|
|
||||||
- The nightly tag for the latest build
|
|
||||||
- A specific SHA for build reproducibility
|
|
||||||
|
|
||||||
### Feedback
|
### Feedback
|
||||||
|
|
||||||
If you encounter any issues with nightly builds, please report them in our
|
If you encounter any issues, please report them in our
|
||||||
[issues tracker](https://github.com/meshtastic/web/issues). Your feedback helps
|
[issues tracker](https://github.com/meshtastic/web/issues). Your feedback helps
|
||||||
improve the stability of future releases
|
improve the stability of future releases
|
||||||
|
|
||||||
## Development & Building
|
|
||||||
|
|
||||||
You'll need to download the package manager used with this repo. You can install
|
|
||||||
it by visiting [deno.com](https://deno.com/) and following the installation
|
|
||||||
instructions listed on the home page.
|
|
||||||
|
|
||||||
### Development
|
|
||||||
|
|
||||||
Install the dependencies.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
deno i
|
|
||||||
```
|
|
||||||
|
|
||||||
Start the development server:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
deno task dev
|
|
||||||
```
|
|
||||||
|
|
||||||
### Building and Packaging
|
|
||||||
|
|
||||||
Build the project:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
deno task build
|
|
||||||
```
|
|
||||||
|
|
||||||
GZip the output:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
deno task package
|
|
||||||
```
|
|
||||||
|
|
||||||
### Why Deno?
|
|
||||||
|
|
||||||
Meshtastic Web uses Deno as its development platform for several compelling
|
|
||||||
reasons:
|
|
||||||
|
|
||||||
- **Built-in Security**: Deno's security-first approach requires explicit
|
|
||||||
permissions for file, network, and environment access, reducing vulnerability
|
|
||||||
risks.
|
|
||||||
- **TypeScript Support**: Native TypeScript support without additional
|
|
||||||
configuration, enhancing code quality and developer experience.
|
|
||||||
- **Modern JavaScript**: First-class support for ESM imports, top-level await,
|
|
||||||
and other modern JavaScript features.
|
|
||||||
- **Simplified Tooling**: Built-in formatter, linter, test runner, and bundler
|
|
||||||
eliminate the need for multiple third-party tools.
|
|
||||||
- **Reproducible Builds**: Lockfile ensures consistent builds across all
|
|
||||||
environments.
|
|
||||||
- **Web Standard APIs**: Uses browser-compatible APIs, making code more portable
|
|
||||||
between server and client environments.
|
|
||||||
|
|
||||||
### Contributing
|
### Contributing
|
||||||
|
|
||||||
We welcome contributions! Here’s how the deployment flow works for pull
|
We welcome contributions! Here’s how the deployment flow works for pull
|
||||||
@@ -170,6 +109,6 @@ requests:
|
|||||||
Meshtastic nodes.
|
Meshtastic nodes.
|
||||||
|
|
||||||
Please review our
|
Please review our
|
||||||
[Contribution Guidelines](https://github.com/meshtastic/web/blob/master/CONTRIBUTING.md)
|
[Contribution Guidelines](https://github.com/meshtastic/web/blob/main/CONTRIBUTING.md)
|
||||||
before submitting a pull request. We appreciate your help in making the project
|
before submitting a pull request. We appreciate your help in making the project
|
||||||
better!
|
better!
|
||||||
|
|||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
{
|
||||||
|
"files": {
|
||||||
|
"includes": [
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
"!npm_modules",
|
||||||
|
"!dist",
|
||||||
|
"!npm",
|
||||||
|
"**/*.json",
|
||||||
|
"!**/locales/*-*/*.json"
|
||||||
|
],
|
||||||
|
"ignoreUnknown": false
|
||||||
|
},
|
||||||
|
"formatter": {
|
||||||
|
"enabled": true,
|
||||||
|
"formatWithErrors": false,
|
||||||
|
"indentStyle": "space",
|
||||||
|
"indentWidth": 2,
|
||||||
|
"lineWidth": 80,
|
||||||
|
"attributePosition": "auto"
|
||||||
|
},
|
||||||
|
"linter": {
|
||||||
|
"enabled": true,
|
||||||
|
"includes": ["**", "!test/**"],
|
||||||
|
"rules": {
|
||||||
|
"recommended": true,
|
||||||
|
"suspicious": {
|
||||||
|
"noExplicitAny": "error",
|
||||||
|
"noDebugger": "error"
|
||||||
|
},
|
||||||
|
"style": {
|
||||||
|
"useBlockStatements": "error",
|
||||||
|
"useSingleVarDeclarator": "off"
|
||||||
|
},
|
||||||
|
"correctness": {
|
||||||
|
"noUnusedVariables": "error",
|
||||||
|
"noUnusedImports": "error",
|
||||||
|
"useImportExtensions": "error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"javascript": {
|
||||||
|
"formatter": {
|
||||||
|
"quoteStyle": "double",
|
||||||
|
"semicolons": "always"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"json": {
|
||||||
|
"formatter": {
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"includes": [
|
||||||
|
"**/*.test.ts",
|
||||||
|
"**/*.test.tsx",
|
||||||
|
"**/__tests__/**/*.{ts,tsx}"
|
||||||
|
],
|
||||||
|
"linter": {
|
||||||
|
"rules": {
|
||||||
|
"suspicious": {
|
||||||
|
"noExplicitAny": "off"
|
||||||
|
},
|
||||||
|
"style": {
|
||||||
|
"noNonNullAssertion": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
{
|
|
||||||
"imports": {
|
|
||||||
"@app/": "./src/",
|
|
||||||
"@pages/": "./src/pages/",
|
|
||||||
"@components/": "./src/components/",
|
|
||||||
"@core/": "./src/core/",
|
|
||||||
"@layouts/": "./src/layouts/"
|
|
||||||
},
|
|
||||||
"compilerOptions": {
|
|
||||||
"lib": [
|
|
||||||
"DOM",
|
|
||||||
"DOM.Iterable",
|
|
||||||
"ESNext",
|
|
||||||
"deno.window",
|
|
||||||
"deno.ns"
|
|
||||||
],
|
|
||||||
"jsx": "react-jsx",
|
|
||||||
"strict": true,
|
|
||||||
"noUnusedLocals": true,
|
|
||||||
"noUnusedParameters": true,
|
|
||||||
"noFallthroughCasesInSwitch": true,
|
|
||||||
"strictNullChecks": true,
|
|
||||||
"types": [
|
|
||||||
"vite/client",
|
|
||||||
"node",
|
|
||||||
"@types/web-bluetooth",
|
|
||||||
"@types/w3c-web-serial"
|
|
||||||
],
|
|
||||||
"strictPropertyInitialization": false
|
|
||||||
},
|
|
||||||
"fmt": {
|
|
||||||
"exclude": [
|
|
||||||
"*.test.ts",
|
|
||||||
"*.test.tsx"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"exclude": [
|
|
||||||
"*.test.ts",
|
|
||||||
"*.test.tsx"
|
|
||||||
],
|
|
||||||
"report": "pretty"
|
|
||||||
},
|
|
||||||
"unstable": [
|
|
||||||
"sloppy-imports"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
FROM nginx:1.27-alpine
|
|
||||||
|
|
||||||
RUN rm -r /usr/share/nginx/html \
|
|
||||||
&& mkdir -p /usr/share/nginx/html \
|
|
||||||
&& mkdir -p /etc/nginx/conf.d
|
|
||||||
|
|
||||||
WORKDIR /usr/share/nginx/html
|
|
||||||
|
|
||||||
ADD dist .
|
|
||||||
|
|
||||||
COPY ./infra/default.conf /etc/nginx/conf.d/default.conf
|
|
||||||
|
|
||||||
EXPOSE 8080
|
|
||||||
|
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
server {
|
|
||||||
listen 8080;
|
|
||||||
server_name localhost;
|
|
||||||
|
|
||||||
root /usr/share/nginx/html;
|
|
||||||
index index.html index.htm;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
try_files $uri $uri/ =404;
|
|
||||||
}
|
|
||||||
|
|
||||||
error_page 500 502 503 504 /50x.html;
|
|
||||||
location = /50x.html {
|
|
||||||
internal;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ /\.ht {
|
|
||||||
deny all;
|
|
||||||
}
|
|
||||||
|
|
||||||
gzip on;
|
|
||||||
gzip_disable "msie6";
|
|
||||||
|
|
||||||
gzip_vary on;
|
|
||||||
gzip_proxied any;
|
|
||||||
gzip_comp_level 6;
|
|
||||||
gzip_buffers 16 8k;
|
|
||||||
gzip_http_version 1.1;
|
|
||||||
gzip_types
|
|
||||||
text/plain
|
|
||||||
text/css
|
|
||||||
text/xml
|
|
||||||
text/javascript
|
|
||||||
application/javascript
|
|
||||||
application/x-javascript
|
|
||||||
application/json
|
|
||||||
application/xml
|
|
||||||
application/xml+rss
|
|
||||||
font/ttf
|
|
||||||
font/otf
|
|
||||||
image/svg+xml;
|
|
||||||
}
|
|
||||||
+36
-95
@@ -1,21 +1,9 @@
|
|||||||
{
|
{
|
||||||
"name": "meshtastic-web",
|
"name": "@meshtastic/web",
|
||||||
"version": "2.6.0-0",
|
"version": "2.7.0-0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Meshtastic web client",
|
"description": "Meshtastic web client monorepo",
|
||||||
"license": "GPL-3.0-only",
|
"license": "GPL-3.0-only",
|
||||||
"scripts": {
|
|
||||||
"build": "vite build",
|
|
||||||
"build:analyze": "BUNDLE_ANALYZE=true deno task build",
|
|
||||||
"lint": "deno lint src/",
|
|
||||||
"lint:fix": "deno lint --fix src/",
|
|
||||||
"format": "deno fmt src/",
|
|
||||||
"dev": "deno task dev:ui",
|
|
||||||
"dev:ui": "deno run -A npm:vite dev",
|
|
||||||
"test": "deno run -A npm:vitest",
|
|
||||||
"preview": "deno run -A npm:vite preview",
|
|
||||||
"package": "gzipper c -i html,js,css,png,ico,svg,webmanifest,txt dist dist/output && tar -cvf dist/build.tar -C ./dist/output/ ."
|
|
||||||
},
|
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/meshtastic/web.git"
|
"url": "git+https://github.com/meshtastic/web.git"
|
||||||
@@ -23,89 +11,42 @@
|
|||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/meshtastic/web/issues"
|
"url": "https://github.com/meshtastic/web/issues"
|
||||||
},
|
},
|
||||||
"simple-git-hooks": {
|
|
||||||
"pre-commit": "deno task lint:fix && deno task format"
|
|
||||||
},
|
|
||||||
"lint-staged": {
|
|
||||||
"*.{ts,tsx}": [
|
|
||||||
"deno task lint:fix",
|
|
||||||
"deno task format"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"homepage": "https://meshtastic.org",
|
"homepage": "https://meshtastic.org",
|
||||||
|
"simple-git-hooks": {
|
||||||
|
"pre-commit": "pnpm run check:fix"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"preinstall": "npx only-allow pnpm",
|
||||||
|
"lint": "biome lint",
|
||||||
|
"lint:fix": "biome lint --write",
|
||||||
|
"format": "biome format",
|
||||||
|
"format:fix": "biome format . --write",
|
||||||
|
"check": "biome check",
|
||||||
|
"check:fix": "biome check --write",
|
||||||
|
"build:all": "pnpm run --filter '*' build",
|
||||||
|
"clean:all": "pnpm run --filter '*' clean",
|
||||||
|
"publish:packages": "pnpm run build --filter 'packages/transport-*'",
|
||||||
|
"test": "vitest"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@meshtastic/core": "npm:@jsr/meshtastic__core@2.6.2",
|
"@bufbuild/protobuf": "^2.9.0",
|
||||||
"@meshtastic/js": "npm:@jsr/meshtastic__js@2.6.0-0",
|
"@meshtastic/protobufs": "npm:@jsr/meshtastic__protobufs@^2.7.12-1",
|
||||||
"@meshtastic/transport-http": "npm:@jsr/meshtastic__transport-http",
|
"ste-simple-events": "^3.0.11",
|
||||||
"@meshtastic/transport-web-bluetooth": "npm:@jsr/meshtastic__transport-web-bluetooth",
|
"tslog": "^4.9.3"
|
||||||
"@meshtastic/transport-web-serial": "npm:@jsr/meshtastic__transport-web-serial",
|
|
||||||
"@bufbuild/protobuf": "^2.2.5",
|
|
||||||
"@noble/curves": "^1.9.0",
|
|
||||||
"@radix-ui/react-accordion": "^1.2.8",
|
|
||||||
"@radix-ui/react-checkbox": "^1.2.3",
|
|
||||||
"@radix-ui/react-dialog": "^1.1.11",
|
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.12",
|
|
||||||
"@radix-ui/react-label": "^2.1.4",
|
|
||||||
"@radix-ui/react-menubar": "^1.1.12",
|
|
||||||
"@radix-ui/react-popover": "^1.1.11",
|
|
||||||
"@radix-ui/react-scroll-area": "^1.2.6",
|
|
||||||
"@radix-ui/react-select": "^2.2.2",
|
|
||||||
"@radix-ui/react-separator": "^1.1.4",
|
|
||||||
"@radix-ui/react-slider": "^1.3.2",
|
|
||||||
"@radix-ui/react-switch": "^1.2.2",
|
|
||||||
"@radix-ui/react-tabs": "^1.1.9",
|
|
||||||
"@radix-ui/react-toast": "^1.2.11",
|
|
||||||
"@radix-ui/react-tooltip": "^1.2.4",
|
|
||||||
"@turf/turf": "^7.2.0",
|
|
||||||
"base64-js": "^1.5.1",
|
|
||||||
"class-validator": "^0.14.2",
|
|
||||||
"class-variance-authority": "^0.7.1",
|
|
||||||
"clsx": "^2.1.1",
|
|
||||||
"cmdk": "^1.1.1",
|
|
||||||
"crypto-random-string": "^5.0.0",
|
|
||||||
"idb-keyval": "^6.2.1",
|
|
||||||
"immer": "^10.1.1",
|
|
||||||
"js-cookie": "^3.0.5",
|
|
||||||
"lucide-react": "^0.507.0",
|
|
||||||
"maplibre-gl": "5.4.0",
|
|
||||||
"react": "^19.1.0",
|
|
||||||
"react-dom": "^19.1.0",
|
|
||||||
"react-error-boundary": "^6.0.0",
|
|
||||||
"react-hook-form": "^7.56.2",
|
|
||||||
"react-map-gl": "8.0.4",
|
|
||||||
"react-qrcode-logo": "^3.0.0",
|
|
||||||
"rfc4648": "^1.5.4",
|
|
||||||
"vite-plugin-node-polyfills": "^0.23.0",
|
|
||||||
"zod": "^3.24.3",
|
|
||||||
"zustand": "5.0.4"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/postcss": "^4.1.5",
|
"@types/node": "^24.3.1",
|
||||||
"@testing-library/jest-dom": "^6.6.3",
|
"@biomejs/biome": "2.2.4",
|
||||||
"@testing-library/react": "^16.3.0",
|
"tsdown": "^0.15.0",
|
||||||
"@testing-library/user-event": "^14.6.1",
|
"typescript": "^5.9.2",
|
||||||
"@types/chrome": "^0.0.318",
|
"vitest": "^3.2.4"
|
||||||
"@types/js-cookie": "^3.0.6",
|
},
|
||||||
"@types/node": "^22.15.3",
|
"pnpm": {
|
||||||
"@types/react": "^19.1.2",
|
"onlyBuiltDependencies": [
|
||||||
"@types/react-dom": "^19.1.3",
|
"@tailwindcss/oxide",
|
||||||
"@types/serviceworker": "^0.0.133",
|
"core-js",
|
||||||
"@types/w3c-web-serial": "^1.0.8",
|
"esbuild",
|
||||||
"@types/web-bluetooth": "^0.0.21",
|
"simple-git-hooks"
|
||||||
"@vitejs/plugin-react": "^4.4.1",
|
]
|
||||||
"autoprefixer": "^10.4.21",
|
|
||||||
"gzipper": "^8.2.1",
|
|
||||||
"happy-dom": "^17.4.6",
|
|
||||||
"postcss": "^8.5.3",
|
|
||||||
"simple-git-hooks": "^2.13.0",
|
|
||||||
"tailwind-merge": "^3.2.0",
|
|
||||||
"tailwindcss": "^4.1.5",
|
|
||||||
"tailwindcss-animate": "^1.0.7",
|
|
||||||
"tar": "^7.4.3",
|
|
||||||
"testing-library": "^0.0.2",
|
|
||||||
"typescript": "^5.8.3",
|
|
||||||
"vite": "^6.3.4",
|
|
||||||
"vitest": "^3.1.2",
|
|
||||||
"vite-plugin-pwa": "^1.0.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# @meshtastic/core
|
||||||
|
|
||||||
|
[](https://jsr.io/@meshtastic/core)
|
||||||
|
[](https://github.com/meshtastic/js/actions/workflows/ci.yml)
|
||||||
|
[](https://cla-assistant.io/meshtastic/meshtastic.js)
|
||||||
|
[](https://opencollective.com/meshtastic/)
|
||||||
|
[](https://vercel.com?utm_source=meshtastic&utm_campaign=oss)
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
`@meshtastic/core` Provides core functionality for interfacing with Meshtastic
|
||||||
|
devices. Installation instructions are available at
|
||||||
|
[JSR](https://jsr.io/@meshtastic/core)
|
||||||
|
[NPM](https://www.npmjs.com/org/meshtastic)
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { MeshDevice } from "@meshtastic/core";
|
||||||
|
|
||||||
|
// Transport if provided by one of the available transport adapters
|
||||||
|
const device = new MeshDevice(transport);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Stats
|
||||||
|
|
||||||
|

|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export * as Protobuf from "@meshtastic/protobufs";
|
||||||
|
export { Constants } from "./src/constants.ts";
|
||||||
|
export { MeshDevice } from "./src/meshDevice.ts";
|
||||||
|
export * as Types from "./src/types.ts";
|
||||||
|
export * as Utils from "./src/utils/mod.ts";
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"name": "@meshtastic/core",
|
||||||
|
"version": "2.6.7",
|
||||||
|
"description": "Core functionalities for Meshtastic web applications.",
|
||||||
|
"exports": {
|
||||||
|
".": "./mod.ts"
|
||||||
|
},
|
||||||
|
"type": "module",
|
||||||
|
"main": "./dist/mod.js",
|
||||||
|
"module": "./dist/mod.js",
|
||||||
|
"types": "./dist/mod.d.ts",
|
||||||
|
"license": "GPL-3.0-only",
|
||||||
|
"tsdown": {
|
||||||
|
"entry": "mod.ts",
|
||||||
|
"dts": true,
|
||||||
|
"format": [
|
||||||
|
"esm"
|
||||||
|
],
|
||||||
|
"splitting": false,
|
||||||
|
"clean": true
|
||||||
|
},
|
||||||
|
"jsrInclude": [
|
||||||
|
"mod.ts",
|
||||||
|
"src",
|
||||||
|
"README.md",
|
||||||
|
"LICENSE"
|
||||||
|
],
|
||||||
|
"jsrExclude": [
|
||||||
|
"src/**/*.test.ts"
|
||||||
|
],
|
||||||
|
"files": [
|
||||||
|
"package.json",
|
||||||
|
"README.md",
|
||||||
|
"LICENSE",
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"preinstall": "npx only-allow pnpm",
|
||||||
|
"prepack": "cp ../../LICENSE ./LICENSE",
|
||||||
|
"clean": "rm -rf dist LICENSE",
|
||||||
|
"build:npm": "tsdown",
|
||||||
|
"publish:npm": "pnpm clean && pnpm build:npm && pnpm publish --access public --no-git-checks",
|
||||||
|
"prepare:jsr": "rm -rf dist && pnpm dlx pkg-to-jsr",
|
||||||
|
"publish:jsr": "pnpm run prepack && pnpm prepare:jsr && deno publish --allow-dirty --no-check"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"crc": "npm:crc@^4.3.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/** Broadcast destination number */
|
||||||
|
const broadcastNum = 0xffffffff;
|
||||||
|
|
||||||
|
/** Minimum device firmware version supported by this version of the library. */
|
||||||
|
const minFwVer = 2.2;
|
||||||
|
|
||||||
|
export const Constants = {
|
||||||
|
broadcastNum,
|
||||||
|
minFwVer,
|
||||||
|
};
|
||||||
Executable
+1244
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,136 @@
|
|||||||
|
import type * as Protobuf from "@meshtastic/protobufs";
|
||||||
|
|
||||||
|
interface Packet {
|
||||||
|
type: "packet";
|
||||||
|
data: Uint8Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DebugLog {
|
||||||
|
type: "debug";
|
||||||
|
data: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StatusEvent {
|
||||||
|
type: "status";
|
||||||
|
data: { status: DeviceStatusEnum; reason?: string };
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DeviceOutput = Packet | DebugLog | StatusEvent;
|
||||||
|
|
||||||
|
export interface Transport {
|
||||||
|
toDevice: WritableStream<Uint8Array>;
|
||||||
|
fromDevice: ReadableStream<DeviceOutput>;
|
||||||
|
disconnect(): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface QueueItem {
|
||||||
|
id: number;
|
||||||
|
data: Uint8Array;
|
||||||
|
sent: boolean;
|
||||||
|
added: Date;
|
||||||
|
promise: Promise<number>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HttpRetryConfig {
|
||||||
|
maxRetries: number;
|
||||||
|
initialDelayMs: number;
|
||||||
|
maxDelayMs: number;
|
||||||
|
backoffFactor: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum DeviceStatusEnum {
|
||||||
|
DeviceRestarting = 1,
|
||||||
|
DeviceDisconnected = 2,
|
||||||
|
DeviceConnecting = 3,
|
||||||
|
DeviceReconnecting = 4,
|
||||||
|
DeviceConnected = 5,
|
||||||
|
DeviceConfiguring = 6,
|
||||||
|
DeviceConfigured = 7,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LogEventPacket = LogEvent & { date: Date };
|
||||||
|
|
||||||
|
export type PacketDestination = "broadcast" | "direct";
|
||||||
|
|
||||||
|
export interface PacketMetadata<T> {
|
||||||
|
id: number;
|
||||||
|
rxTime: Date;
|
||||||
|
type: PacketDestination;
|
||||||
|
from: number;
|
||||||
|
to: number;
|
||||||
|
channel: ChannelNumber;
|
||||||
|
data: T;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum EmitterScope {
|
||||||
|
MeshDevice = 1,
|
||||||
|
SerialConnection = 2,
|
||||||
|
NodeSerialConnection = 3,
|
||||||
|
BleConnection = 4,
|
||||||
|
HttpConnection = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum Emitter {
|
||||||
|
Constructor = 0,
|
||||||
|
SendText = 1,
|
||||||
|
SendWaypoint = 2,
|
||||||
|
SendPacket = 3,
|
||||||
|
SendRaw = 4,
|
||||||
|
SetConfig = 5,
|
||||||
|
SetModuleConfig = 6,
|
||||||
|
ConfirmSetConfig = 7,
|
||||||
|
SetOwner = 8,
|
||||||
|
SetChannel = 9,
|
||||||
|
ConfirmSetChannel = 10,
|
||||||
|
ClearChannel = 11,
|
||||||
|
GetChannel = 12,
|
||||||
|
GetAllChannels = 13,
|
||||||
|
GetConfig = 14,
|
||||||
|
GetModuleConfig = 15,
|
||||||
|
GetOwner = 16,
|
||||||
|
Configure = 17,
|
||||||
|
HandleFromRadio = 18,
|
||||||
|
HandleMeshPacket = 19,
|
||||||
|
Connect = 20,
|
||||||
|
Ping = 21,
|
||||||
|
ReadFromRadio = 22,
|
||||||
|
WriteToRadio = 23,
|
||||||
|
SetDebugMode = 24,
|
||||||
|
GetMetadata = 25,
|
||||||
|
ResetNodes = 26,
|
||||||
|
Shutdown = 27,
|
||||||
|
Reboot = 28,
|
||||||
|
RebootOta = 29,
|
||||||
|
FactoryReset = 30,
|
||||||
|
EnterDfuMode = 31,
|
||||||
|
RemoveNodeByNum = 32,
|
||||||
|
SetCannedMessages = 33,
|
||||||
|
Disconnect = 34,
|
||||||
|
ConnectionStatus = 35,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LogEvent {
|
||||||
|
scope: EmitterScope;
|
||||||
|
emitter: Emitter;
|
||||||
|
message: string;
|
||||||
|
level: Protobuf.Mesh.LogRecord_Level;
|
||||||
|
packet?: Uint8Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ChannelNumber {
|
||||||
|
Primary = 0,
|
||||||
|
Channel1 = 1,
|
||||||
|
Channel2 = 2,
|
||||||
|
Channel3 = 3,
|
||||||
|
Channel4 = 4,
|
||||||
|
Channel5 = 5,
|
||||||
|
Channel6 = 6,
|
||||||
|
Admin = 7,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Destination = number | "self" | "broadcast";
|
||||||
|
|
||||||
|
export interface PacketError {
|
||||||
|
id: number;
|
||||||
|
error: Protobuf.Mesh.Routing_Error;
|
||||||
|
}
|
||||||
@@ -0,0 +1,390 @@
|
|||||||
|
import type * as Protobuf from "@meshtastic/protobufs";
|
||||||
|
import { SimpleEventDispatcher } from "ste-simple-events";
|
||||||
|
import type * as Types from "../types.ts";
|
||||||
|
import type { PacketMetadata } from "../types.ts";
|
||||||
|
|
||||||
|
export class EventSystem {
|
||||||
|
/**
|
||||||
|
* Fires when a new FromRadio message has been received from the device
|
||||||
|
*
|
||||||
|
* @event onLogEvent
|
||||||
|
*/
|
||||||
|
public readonly onLogEvent: SimpleEventDispatcher<Types.LogEventPacket> =
|
||||||
|
new SimpleEventDispatcher<Types.LogEventPacket>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new FromRadio message has been received from the device
|
||||||
|
*
|
||||||
|
* @event onFromRadio
|
||||||
|
*/
|
||||||
|
public readonly onFromRadio: SimpleEventDispatcher<Protobuf.Mesh.FromRadio> =
|
||||||
|
new SimpleEventDispatcher<Protobuf.Mesh.FromRadio>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new FromRadio message containing a Data packet has been
|
||||||
|
* received from the device
|
||||||
|
*
|
||||||
|
* @event onMeshPacket
|
||||||
|
*/
|
||||||
|
public readonly onMeshPacket: SimpleEventDispatcher<Protobuf.Mesh.MeshPacket> =
|
||||||
|
new SimpleEventDispatcher<Protobuf.Mesh.MeshPacket>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MyNodeInfo message has been received from the device
|
||||||
|
*
|
||||||
|
* @event onMyNodeInfo
|
||||||
|
*/
|
||||||
|
public readonly onMyNodeInfo: SimpleEventDispatcher<Protobuf.Mesh.MyNodeInfo> =
|
||||||
|
new SimpleEventDispatcher<Protobuf.Mesh.MyNodeInfo>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a NodeInfo packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onNodeInfoPacket
|
||||||
|
*/
|
||||||
|
public readonly onNodeInfoPacket: SimpleEventDispatcher<Protobuf.Mesh.NodeInfo> =
|
||||||
|
new SimpleEventDispatcher<Protobuf.Mesh.NodeInfo>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new Channel message is received
|
||||||
|
*
|
||||||
|
* @event onChannelPacket
|
||||||
|
*/
|
||||||
|
public readonly onChannelPacket: SimpleEventDispatcher<Protobuf.Channel.Channel> =
|
||||||
|
new SimpleEventDispatcher<Protobuf.Channel.Channel>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new Config message is received
|
||||||
|
*
|
||||||
|
* @event onConfigPacket
|
||||||
|
*/
|
||||||
|
public readonly onConfigPacket: SimpleEventDispatcher<Protobuf.Config.Config> =
|
||||||
|
new SimpleEventDispatcher<Protobuf.Config.Config>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new ModuleConfig message is received
|
||||||
|
*
|
||||||
|
* @event onModuleConfigPacket
|
||||||
|
*/
|
||||||
|
public readonly onModuleConfigPacket: SimpleEventDispatcher<Protobuf.ModuleConfig.ModuleConfig> =
|
||||||
|
new SimpleEventDispatcher<Protobuf.ModuleConfig.ModuleConfig>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a ATAK packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onAtakPacket
|
||||||
|
*/
|
||||||
|
public readonly onAtakPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Uint8Array>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a Text packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onMessagePacket
|
||||||
|
*/
|
||||||
|
public readonly onMessagePacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<string>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<string>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a Remote Hardware packet has
|
||||||
|
* been received from device
|
||||||
|
*
|
||||||
|
* @event onRemoteHardwarePacket
|
||||||
|
*/
|
||||||
|
public readonly onRemoteHardwarePacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Protobuf.RemoteHardware.HardwareMessage>
|
||||||
|
> = new SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Protobuf.RemoteHardware.HardwareMessage>
|
||||||
|
>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a Position packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onPositionPacket
|
||||||
|
*/
|
||||||
|
public readonly onPositionPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Protobuf.Mesh.Position>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Protobuf.Mesh.Position>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a User packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onUserPacket
|
||||||
|
*/
|
||||||
|
public readonly onUserPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Protobuf.Mesh.User>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Protobuf.Mesh.User>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a Routing packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onRoutingPacket
|
||||||
|
*/
|
||||||
|
public readonly onRoutingPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Protobuf.Mesh.Routing>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Protobuf.Mesh.Routing>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when the device receives a Metadata packet
|
||||||
|
*
|
||||||
|
* @event onDeviceMetadataPacket
|
||||||
|
*/
|
||||||
|
public readonly onDeviceMetadataPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Protobuf.Mesh.DeviceMetadata>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Protobuf.Mesh.DeviceMetadata>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when the device receives a Canned Message Module message packet
|
||||||
|
*
|
||||||
|
* @event onCannedMessageModulePacket
|
||||||
|
*/
|
||||||
|
public readonly onCannedMessageModulePacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<string>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<string>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a Waypoint packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onWaypointPacket
|
||||||
|
*/
|
||||||
|
public readonly onWaypointPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Protobuf.Mesh.Waypoint>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Protobuf.Mesh.Waypoint>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing an Audio packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onAudioPacket
|
||||||
|
*/
|
||||||
|
public readonly onAudioPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Uint8Array>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a Detection Sensor packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onDetectionSensorPacket
|
||||||
|
*/
|
||||||
|
public readonly onDetectionSensorPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Uint8Array>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a Ping packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onPingPacket
|
||||||
|
*/
|
||||||
|
public readonly onPingPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Uint8Array>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a IP Tunnel packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onIpTunnelPacket
|
||||||
|
*/
|
||||||
|
public readonly onIpTunnelPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Uint8Array>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a Paxcounter packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onPaxcounterPacket
|
||||||
|
*/
|
||||||
|
public readonly onPaxcounterPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Protobuf.PaxCount.Paxcount>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Protobuf.PaxCount.Paxcount>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a Serial packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onSerialPacket
|
||||||
|
*/
|
||||||
|
public readonly onSerialPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Uint8Array>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a Store and Forward packet
|
||||||
|
* has been received from device
|
||||||
|
*
|
||||||
|
* @event onStoreForwardPacket
|
||||||
|
*/
|
||||||
|
public readonly onStoreForwardPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Uint8Array>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a Store and Forward packet
|
||||||
|
* has been received from device
|
||||||
|
*
|
||||||
|
* @event onRangeTestPacket
|
||||||
|
*/
|
||||||
|
public readonly onRangeTestPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Uint8Array>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a Telemetry packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onTelemetryPacket
|
||||||
|
*/
|
||||||
|
public readonly onTelemetryPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Protobuf.Telemetry.Telemetry>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Protobuf.Telemetry.Telemetry>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a ZPS packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onZPSPacket
|
||||||
|
*/
|
||||||
|
public readonly onZpsPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Uint8Array>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a Simulator packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onSimulatorPacket
|
||||||
|
*/
|
||||||
|
public readonly onSimulatorPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Uint8Array>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a Trace Route packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onTraceRoutePacket
|
||||||
|
*/
|
||||||
|
public readonly onTraceRoutePacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Protobuf.Mesh.RouteDiscovery>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Protobuf.Mesh.RouteDiscovery>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a Neighbor Info packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onNeighborInfoPacket
|
||||||
|
*/
|
||||||
|
public readonly onNeighborInfoPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Protobuf.Mesh.NeighborInfo>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Protobuf.Mesh.NeighborInfo>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing an ATAK packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onAtakPluginPacket
|
||||||
|
*/
|
||||||
|
public readonly onAtakPluginPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Uint8Array>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a Map Report packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onMapReportPacket
|
||||||
|
*/
|
||||||
|
public readonly onMapReportPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Uint8Array>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a Private packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onPrivatePacket
|
||||||
|
*/
|
||||||
|
public readonly onPrivatePacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Uint8Array>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing an ATAK Forwarder packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onAtakForwarderPacket
|
||||||
|
*/
|
||||||
|
public readonly onAtakForwarderPacket: SimpleEventDispatcher<
|
||||||
|
PacketMetadata<Uint8Array>
|
||||||
|
> = new SimpleEventDispatcher<PacketMetadata<Uint8Array>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new MeshPacket message containing a ClientNotification packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onClientNotificationPacket
|
||||||
|
*/
|
||||||
|
public readonly onClientNotificationPacket: SimpleEventDispatcher<Protobuf.Mesh.ClientNotification> =
|
||||||
|
new SimpleEventDispatcher<Protobuf.Mesh.ClientNotification>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when the devices connection or configuration status changes
|
||||||
|
*
|
||||||
|
* @event onDeviceStatus
|
||||||
|
*/
|
||||||
|
public readonly onDeviceStatus: SimpleEventDispatcher<Types.DeviceStatusEnum> =
|
||||||
|
new SimpleEventDispatcher<Types.DeviceStatusEnum>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a new FromRadio message containing a LogRecord packet has been
|
||||||
|
* received from device
|
||||||
|
*
|
||||||
|
* @event onLogRecord
|
||||||
|
*/
|
||||||
|
public readonly onLogRecord: SimpleEventDispatcher<Protobuf.Mesh.LogRecord> =
|
||||||
|
new SimpleEventDispatcher<Protobuf.Mesh.LogRecord>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when the device receives a meshPacket, returns a timestamp
|
||||||
|
*
|
||||||
|
* @event onMeshHeartbeat
|
||||||
|
*/
|
||||||
|
public readonly onMeshHeartbeat: SimpleEventDispatcher<Date> =
|
||||||
|
new SimpleEventDispatcher<Date>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs any debug log data (currently serial connections only)
|
||||||
|
*
|
||||||
|
* @event onDeviceDebugLog
|
||||||
|
*/
|
||||||
|
public readonly onDeviceDebugLog: SimpleEventDispatcher<Uint8Array> =
|
||||||
|
new SimpleEventDispatcher<Uint8Array>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs status of pending settings changes
|
||||||
|
*
|
||||||
|
* @event onpendingSettingsChange
|
||||||
|
*/
|
||||||
|
public readonly onPendingSettingsChange: SimpleEventDispatcher<boolean> =
|
||||||
|
new SimpleEventDispatcher<boolean>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires when a QueueStatus message is generated
|
||||||
|
*
|
||||||
|
* @event onQueueStatus
|
||||||
|
*/
|
||||||
|
public readonly onQueueStatus: SimpleEventDispatcher<Protobuf.Mesh.QueueStatus> =
|
||||||
|
new SimpleEventDispatcher<Protobuf.Mesh.QueueStatus>();
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export { EventSystem } from "./eventSystem.ts";
|
||||||
|
export { Queue } from "./queue.ts";
|
||||||
|
export { fromDeviceStream } from "./transform/fromDevice.ts";
|
||||||
|
export { toDeviceStream } from "./transform/toDevice.ts";
|
||||||
|
export { Xmodem } from "./xmodem.ts";
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
import { fromBinary } from "@bufbuild/protobuf";
|
||||||
|
import * as Protobuf from "@meshtastic/protobufs";
|
||||||
|
import { SimpleEventDispatcher } from "ste-simple-events";
|
||||||
|
import type { PacketError, QueueItem } from "../types.ts";
|
||||||
|
|
||||||
|
export class Queue {
|
||||||
|
private queue: QueueItem[] = [];
|
||||||
|
private lock = false;
|
||||||
|
private ackNotifier = new SimpleEventDispatcher<number>();
|
||||||
|
private errorNotifier = new SimpleEventDispatcher<PacketError>();
|
||||||
|
private timeout: number;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.timeout = 60000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getState(): QueueItem[] {
|
||||||
|
return this.queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public clear(): void {
|
||||||
|
this.queue = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public push(item: Omit<QueueItem, "promise" | "sent" | "added">): void {
|
||||||
|
const queueItem: QueueItem = {
|
||||||
|
...item,
|
||||||
|
sent: false,
|
||||||
|
added: new Date(),
|
||||||
|
promise: new Promise<number>((resolve, reject) => {
|
||||||
|
this.ackNotifier.subscribe((id) => {
|
||||||
|
if (item.id === id) {
|
||||||
|
this.remove(item.id);
|
||||||
|
resolve(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.errorNotifier.subscribe((e) => {
|
||||||
|
if (item.id === e.id) {
|
||||||
|
this.remove(item.id);
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.queue.findIndex((qi) => qi.id === item.id) !== -1) {
|
||||||
|
this.remove(item.id);
|
||||||
|
const decoded = fromBinary(Protobuf.Mesh.ToRadioSchema, item.data);
|
||||||
|
|
||||||
|
if (
|
||||||
|
decoded.payloadVariant.case === "heartbeat" ||
|
||||||
|
decoded.payloadVariant.case === "wantConfigId"
|
||||||
|
) {
|
||||||
|
// heartbeat and wantConfigId packets are not acknowledged by the device, assume success after timeout
|
||||||
|
resolve(item.id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.warn(
|
||||||
|
`Packet ${item.id} of type ${decoded.payloadVariant.case} timed out`,
|
||||||
|
);
|
||||||
|
|
||||||
|
reject({
|
||||||
|
id: item.id,
|
||||||
|
error: Protobuf.Mesh.Routing_Error.TIMEOUT,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, this.timeout);
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
this.queue.push(queueItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
public remove(id: number): void {
|
||||||
|
if (this.lock) {
|
||||||
|
setTimeout(() => this.remove(id), 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.queue = this.queue.filter((item) => item.id !== id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public processAck(id: number): void {
|
||||||
|
this.ackNotifier.dispatch(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public processError(e: PacketError): void {
|
||||||
|
console.error(
|
||||||
|
`Error received for packet ${e.id}: ${
|
||||||
|
Protobuf.Mesh.Routing_Error[e.error]
|
||||||
|
}`,
|
||||||
|
);
|
||||||
|
this.errorNotifier.dispatch(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public wait(id: number): Promise<number> {
|
||||||
|
const queueItem = this.queue.find((qi) => qi.id === id);
|
||||||
|
if (!queueItem) {
|
||||||
|
throw new Error("Packet does not exist");
|
||||||
|
}
|
||||||
|
return queueItem.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async processQueue(
|
||||||
|
outputStream: WritableStream<Uint8Array>,
|
||||||
|
): Promise<void> {
|
||||||
|
if (this.lock) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lock = true;
|
||||||
|
const writer = outputStream.getWriter();
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (this.queue.filter((p) => !p.sent).length > 0) {
|
||||||
|
const item = this.queue.filter((p) => !p.sent)[0];
|
||||||
|
if (item) {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
||||||
|
try {
|
||||||
|
await writer.write(item.data);
|
||||||
|
item.sent = true;
|
||||||
|
} catch (error) {
|
||||||
|
if (
|
||||||
|
error?.code === "ECONNRESET" ||
|
||||||
|
error?.code === "ERR_INVALID_STATE"
|
||||||
|
) {
|
||||||
|
writer.releaseLock();
|
||||||
|
this.lock = false;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
console.error(`Error sending packet ${item.id}`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
writer.releaseLock();
|
||||||
|
this.lock = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
import { fromBinary } from "@bufbuild/protobuf";
|
||||||
|
import type { MeshDevice } from "../../../mod.ts";
|
||||||
|
import { Constants, Protobuf, Types } from "../../../mod.ts";
|
||||||
|
import type { DeviceOutput } from "../../types.ts";
|
||||||
|
|
||||||
|
export const decodePacket = (device: MeshDevice) =>
|
||||||
|
new WritableStream<DeviceOutput>({
|
||||||
|
write(chunk) {
|
||||||
|
switch (chunk.type) {
|
||||||
|
case "status": {
|
||||||
|
const { status, reason } = chunk.data as {
|
||||||
|
status: Types.DeviceStatusEnum;
|
||||||
|
reason?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
device.updateDeviceStatus(status);
|
||||||
|
device.log.info(
|
||||||
|
Types.Emitter[Types.Emitter.ConnectionStatus],
|
||||||
|
`🔗 ${Types.DeviceStatusEnum[status]} ${reason ? `(${reason})` : ""}`,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "debug": {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "packet": {
|
||||||
|
let decodedMessage: Protobuf.Mesh.FromRadio;
|
||||||
|
try {
|
||||||
|
decodedMessage = fromBinary(
|
||||||
|
Protobuf.Mesh.FromRadioSchema,
|
||||||
|
chunk.data,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
device.log.error(
|
||||||
|
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||||
|
"⚠️ Received undecodable packet",
|
||||||
|
e,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
device.events.onFromRadio.dispatch(decodedMessage);
|
||||||
|
|
||||||
|
/** @todo Add map here when `all=true` gets fixed. */
|
||||||
|
switch (decodedMessage.payloadVariant.case) {
|
||||||
|
case "packet": {
|
||||||
|
try {
|
||||||
|
device.handleMeshPacket(decodedMessage.payloadVariant.value);
|
||||||
|
} catch (e) {
|
||||||
|
device.log.error(
|
||||||
|
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||||
|
"⚠️ Unable to handle mesh packet",
|
||||||
|
e,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "myInfo": {
|
||||||
|
device.events.onMyNodeInfo.dispatch(
|
||||||
|
decodedMessage.payloadVariant.value,
|
||||||
|
);
|
||||||
|
device.log.info(
|
||||||
|
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||||
|
"📱 Received Node info for this device",
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "nodeInfo": {
|
||||||
|
device.log.info(
|
||||||
|
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||||
|
`📱 Received Node Info packet for node: ${decodedMessage.payloadVariant.value.num}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
device.events.onNodeInfoPacket.dispatch(
|
||||||
|
decodedMessage.payloadVariant.value,
|
||||||
|
);
|
||||||
|
|
||||||
|
//TODO: HERE
|
||||||
|
if (decodedMessage.payloadVariant.value.position) {
|
||||||
|
device.events.onPositionPacket.dispatch({
|
||||||
|
id: decodedMessage.id,
|
||||||
|
rxTime: new Date(),
|
||||||
|
from: decodedMessage.payloadVariant.value.num,
|
||||||
|
to: decodedMessage.payloadVariant.value.num,
|
||||||
|
type: "direct",
|
||||||
|
channel: Types.ChannelNumber.Primary,
|
||||||
|
data: decodedMessage.payloadVariant.value.position,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: HERE
|
||||||
|
if (decodedMessage.payloadVariant.value.user) {
|
||||||
|
device.events.onUserPacket.dispatch({
|
||||||
|
id: decodedMessage.id,
|
||||||
|
rxTime: new Date(),
|
||||||
|
from: decodedMessage.payloadVariant.value.num,
|
||||||
|
to: decodedMessage.payloadVariant.value.num,
|
||||||
|
type: "direct",
|
||||||
|
channel: Types.ChannelNumber.Primary,
|
||||||
|
data: decodedMessage.payloadVariant.value.user,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "config": {
|
||||||
|
if (decodedMessage.payloadVariant.value.payloadVariant.case) {
|
||||||
|
device.log.trace(
|
||||||
|
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||||
|
`💾 Received Config packet of variant: ${decodedMessage.payloadVariant.value.payloadVariant.case}`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
device.log.warn(
|
||||||
|
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||||
|
`⚠️ Received Config packet of variant: ${"UNK"}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
device.events.onConfigPacket.dispatch(
|
||||||
|
decodedMessage.payloadVariant.value,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "logRecord": {
|
||||||
|
device.log.trace(
|
||||||
|
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||||
|
"Received onLogRecord",
|
||||||
|
);
|
||||||
|
device.events.onLogRecord.dispatch(
|
||||||
|
decodedMessage.payloadVariant.value,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "configCompleteId": {
|
||||||
|
if (decodedMessage.payloadVariant.value !== device.configId) {
|
||||||
|
device.log.error(
|
||||||
|
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||||
|
`❌ Invalid config id received from device, expected ${device.configId} but received ${decodedMessage.payloadVariant.value}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
device.log.info(
|
||||||
|
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||||
|
`⚙️ Valid config id received from device: ${device.configId}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
device.updateDeviceStatus(
|
||||||
|
Types.DeviceStatusEnum.DeviceConfigured,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "rebooted": {
|
||||||
|
device.configure().catch(() => {
|
||||||
|
// TODO: FIX, workaround for `wantConfigId` not getting acks.
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "moduleConfig": {
|
||||||
|
if (decodedMessage.payloadVariant.value.payloadVariant.case) {
|
||||||
|
device.log.trace(
|
||||||
|
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||||
|
`💾 Received Module Config packet of variant: ${decodedMessage.payloadVariant.value.payloadVariant.case}`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
device.log.warn(
|
||||||
|
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||||
|
"⚠️ Received Module Config packet of variant: UNK",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
device.events.onModuleConfigPacket.dispatch(
|
||||||
|
decodedMessage.payloadVariant.value,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "channel": {
|
||||||
|
device.log.trace(
|
||||||
|
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||||
|
`🔐 Received Channel: ${decodedMessage.payloadVariant.value.index}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
device.events.onChannelPacket.dispatch(
|
||||||
|
decodedMessage.payloadVariant.value,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "queueStatus": {
|
||||||
|
device.log.trace(
|
||||||
|
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||||
|
`🚧 Received Queue Status: ${decodedMessage.payloadVariant.value}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
device.events.onQueueStatus.dispatch(
|
||||||
|
decodedMessage.payloadVariant.value,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "xmodemPacket": {
|
||||||
|
device.xModem.handlePacket(decodedMessage.payloadVariant.value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "metadata": {
|
||||||
|
if (
|
||||||
|
Number.parseFloat(
|
||||||
|
decodedMessage.payloadVariant.value.firmwareVersion,
|
||||||
|
) < Constants.minFwVer
|
||||||
|
) {
|
||||||
|
device.log.fatal(
|
||||||
|
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||||
|
`Device firmware outdated. Min supported: ${Constants.minFwVer} got : ${decodedMessage.payloadVariant.value.firmwareVersion}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
device.log.debug(
|
||||||
|
Types.Emitter[Types.Emitter.GetMetadata],
|
||||||
|
"🏷️ Received metadata packet",
|
||||||
|
);
|
||||||
|
|
||||||
|
device.events.onDeviceMetadataPacket.dispatch({
|
||||||
|
id: decodedMessage.id,
|
||||||
|
rxTime: new Date(),
|
||||||
|
from: 0,
|
||||||
|
to: 0,
|
||||||
|
type: "direct",
|
||||||
|
channel: Types.ChannelNumber.Primary,
|
||||||
|
data: decodedMessage.payloadVariant.value,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "mqttClientProxyMessage": {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "clientNotification": {
|
||||||
|
device.log.trace(
|
||||||
|
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||||
|
`📣 Received ClientNotification: ${decodedMessage.payloadVariant.value.message}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
device.events.onClientNotificationPacket.dispatch(
|
||||||
|
decodedMessage.payloadVariant.value,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
device.log.warn(
|
||||||
|
Types.Emitter[Types.Emitter.HandleFromRadio],
|
||||||
|
`⚠️ Unhandled payload variant: ${decodedMessage.payloadVariant.case}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import type { DeviceOutput } from "../../types.ts";
|
||||||
|
|
||||||
|
export const fromDeviceStream: () => TransformStream<Uint8Array, DeviceOutput> =
|
||||||
|
(
|
||||||
|
// onReleaseEvent: SimpleEventDispatcher<boolean>,
|
||||||
|
) => {
|
||||||
|
let byteBuffer = new Uint8Array([]);
|
||||||
|
const textDecoder = new TextDecoder();
|
||||||
|
return new TransformStream<Uint8Array, DeviceOutput>({
|
||||||
|
transform(chunk: Uint8Array, controller): void {
|
||||||
|
// onReleaseEvent.subscribe(() => {
|
||||||
|
// controller.terminate();
|
||||||
|
// });
|
||||||
|
byteBuffer = new Uint8Array([...byteBuffer, ...chunk]);
|
||||||
|
let processingExhausted = false;
|
||||||
|
while (byteBuffer.length !== 0 && !processingExhausted) {
|
||||||
|
const framingIndex = byteBuffer.indexOf(0x94);
|
||||||
|
const framingByte2 = byteBuffer[framingIndex + 1];
|
||||||
|
if (framingByte2 === 0xc3) {
|
||||||
|
if (byteBuffer.subarray(0, framingIndex).length) {
|
||||||
|
controller.enqueue({
|
||||||
|
type: "debug",
|
||||||
|
data: textDecoder.decode(byteBuffer.subarray(0, framingIndex)),
|
||||||
|
});
|
||||||
|
byteBuffer = byteBuffer.subarray(framingIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
const msb = byteBuffer[2];
|
||||||
|
const lsb = byteBuffer[3];
|
||||||
|
|
||||||
|
if (
|
||||||
|
msb !== undefined &&
|
||||||
|
lsb !== undefined &&
|
||||||
|
byteBuffer.length >= 4 + (msb << 8) + lsb
|
||||||
|
) {
|
||||||
|
const packet = byteBuffer.subarray(4, 4 + (msb << 8) + lsb);
|
||||||
|
|
||||||
|
const malformedDetectorIndex = packet.indexOf(0x94);
|
||||||
|
if (
|
||||||
|
malformedDetectorIndex !== -1 &&
|
||||||
|
packet[malformedDetectorIndex + 1] === 0xc3
|
||||||
|
) {
|
||||||
|
console.warn(
|
||||||
|
`⚠️ Malformed packet found, discarding: ${byteBuffer
|
||||||
|
.subarray(0, malformedDetectorIndex - 1)
|
||||||
|
.toString()}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
byteBuffer = byteBuffer.subarray(malformedDetectorIndex);
|
||||||
|
} else {
|
||||||
|
byteBuffer = byteBuffer.subarray(3 + (msb << 8) + lsb + 1);
|
||||||
|
|
||||||
|
controller.enqueue({
|
||||||
|
type: "packet",
|
||||||
|
data: packet,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/** Only partioal message in buffer, wait for the rest */
|
||||||
|
processingExhausted = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/** Message not complete, only 1 byte in buffer */
|
||||||
|
processingExhausted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* Pads packets with appropriate framing information before writing to the output stream.
|
||||||
|
*/
|
||||||
|
export const toDeviceStream: () => TransformStream<Uint8Array, Uint8Array> =
|
||||||
|
() => {
|
||||||
|
return new TransformStream<Uint8Array, Uint8Array>({
|
||||||
|
transform(chunk: Uint8Array, controller): void {
|
||||||
|
const bufLen = chunk.length;
|
||||||
|
const header = new Uint8Array([
|
||||||
|
0x94,
|
||||||
|
0xc3,
|
||||||
|
(bufLen >> 8) & 0xff,
|
||||||
|
bufLen & 0xff,
|
||||||
|
]);
|
||||||
|
controller.enqueue(new Uint8Array([...header, ...chunk]));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
import { create, toBinary } from "@bufbuild/protobuf";
|
||||||
|
import * as Protobuf from "@meshtastic/protobufs";
|
||||||
|
import crc16ccitt from "crc/calculators/crc16ccitt";
|
||||||
|
|
||||||
|
//if counter > 35 then reset counter/clear/error/reject promise
|
||||||
|
type XmodemProps = (toRadio: Uint8Array, id?: number) => Promise<number>;
|
||||||
|
|
||||||
|
export class Xmodem {
|
||||||
|
private sendRaw: XmodemProps;
|
||||||
|
private rxBuffer: Uint8Array[];
|
||||||
|
private txBuffer: Uint8Array[];
|
||||||
|
private textEncoder: TextEncoder;
|
||||||
|
private counter: number;
|
||||||
|
|
||||||
|
constructor(sendRaw: XmodemProps) {
|
||||||
|
this.sendRaw = sendRaw;
|
||||||
|
this.rxBuffer = [];
|
||||||
|
this.txBuffer = [];
|
||||||
|
this.textEncoder = new TextEncoder();
|
||||||
|
this.counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async downloadFile(filename: string): Promise<number> {
|
||||||
|
return await this.sendCommand(
|
||||||
|
Protobuf.Xmodem.XModem_Control.STX,
|
||||||
|
this.textEncoder.encode(filename),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async uploadFile(filename: string, data: Uint8Array): Promise<number> {
|
||||||
|
for (let i = 0; i < data.length; i += 128) {
|
||||||
|
this.txBuffer.push(data.slice(i, i + 128));
|
||||||
|
}
|
||||||
|
|
||||||
|
return await this.sendCommand(
|
||||||
|
Protobuf.Xmodem.XModem_Control.SOH,
|
||||||
|
this.textEncoder.encode(filename),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendCommand(
|
||||||
|
command: Protobuf.Xmodem.XModem_Control,
|
||||||
|
buffer?: Uint8Array,
|
||||||
|
sequence?: number,
|
||||||
|
crc16?: number,
|
||||||
|
): Promise<number> {
|
||||||
|
const toRadio = create(Protobuf.Mesh.ToRadioSchema, {
|
||||||
|
payloadVariant: {
|
||||||
|
case: "xmodemPacket",
|
||||||
|
value: {
|
||||||
|
buffer,
|
||||||
|
control: command,
|
||||||
|
seq: sequence,
|
||||||
|
crc16: crc16,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return await this.sendRaw(toBinary(Protobuf.Mesh.ToRadioSchema, toRadio));
|
||||||
|
}
|
||||||
|
|
||||||
|
async handlePacket(packet: Protobuf.Xmodem.XModem): Promise<number> {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||||
|
|
||||||
|
switch (packet.control) {
|
||||||
|
case Protobuf.Xmodem.XModem_Control.NUL: {
|
||||||
|
// nothing
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Protobuf.Xmodem.XModem_Control.SOH: {
|
||||||
|
this.counter = packet.seq;
|
||||||
|
if (this.validateCrc16(packet)) {
|
||||||
|
this.rxBuffer[this.counter] = packet.buffer;
|
||||||
|
return this.sendCommand(Protobuf.Xmodem.XModem_Control.ACK);
|
||||||
|
}
|
||||||
|
return await this.sendCommand(
|
||||||
|
Protobuf.Xmodem.XModem_Control.NAK,
|
||||||
|
undefined,
|
||||||
|
packet.seq,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case Protobuf.Xmodem.XModem_Control.STX: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Protobuf.Xmodem.XModem_Control.EOT: {
|
||||||
|
// end of transmission
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Protobuf.Xmodem.XModem_Control.ACK: {
|
||||||
|
this.counter++;
|
||||||
|
if (this.txBuffer[this.counter - 1]) {
|
||||||
|
return this.sendCommand(
|
||||||
|
Protobuf.Xmodem.XModem_Control.SOH,
|
||||||
|
this.txBuffer[this.counter - 1],
|
||||||
|
this.counter,
|
||||||
|
crc16ccitt(this.txBuffer[this.counter - 1] ?? new Uint8Array()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (this.counter === this.txBuffer.length + 1) {
|
||||||
|
return this.sendCommand(Protobuf.Xmodem.XModem_Control.EOT);
|
||||||
|
}
|
||||||
|
this.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Protobuf.Xmodem.XModem_Control.NAK: {
|
||||||
|
return this.sendCommand(
|
||||||
|
Protobuf.Xmodem.XModem_Control.SOH,
|
||||||
|
this.txBuffer[this.counter],
|
||||||
|
this.counter,
|
||||||
|
crc16ccitt(this.txBuffer[this.counter - 1] ?? new Uint8Array()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case Protobuf.Xmodem.XModem_Control.CAN: {
|
||||||
|
this.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Protobuf.Xmodem.XModem_Control.CTRLZ: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
validateCrc16(packet: Protobuf.Xmodem.XModem): boolean {
|
||||||
|
return crc16ccitt(packet.buffer) === packet.crc16;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this.counter = 0;
|
||||||
|
this.rxBuffer = [];
|
||||||
|
this.txBuffer = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "ESNext",
|
||||||
|
"target": "ES2020",
|
||||||
|
"declaration": true,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"emitDeclarationOnly": false,
|
||||||
|
"esModuleInterop": true
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
||||||
Submodule
+1
Submodule packages/packages/protobufs added at a1b8c3d171
@@ -0,0 +1,3 @@
|
|||||||
|
* text=auto eol=lf
|
||||||
|
*.{cmd,[cC][mM][dD]} text eol=crlf
|
||||||
|
*.{bat,[bB][aA][tT]} text eol=crlf
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<!-- Describe what you are intending to change -->
|
||||||
|
|
||||||
|
# What does this PR do?
|
||||||
|
|
||||||
|
<!-- Please remove or replace the issue url -->
|
||||||
|
|
||||||
|
> [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.
|
||||||
+24
@@ -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
|
||||||
@@ -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 }}
|
||||||
@@ -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 }}
|
||||||
@@ -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
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
.DS_Store
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
[submodule "packages/protobufs"]
|
||||||
|
branch = master
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"recommendations": ["pbkit.vscode-pbkit", "bufbuild.vscode-buf"]
|
||||||
|
}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.defaultFormatter": "pbkit.vscode-pbkit"
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|
||||||
|

|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
version: v2
|
||||||
|
plugins:
|
||||||
|
- remote: buf.build/bufbuild/es
|
||||||
|
out: packages/ts/dist
|
||||||
|
opt: target=ts
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
version: v1
|
||||||
|
name: buf.build/meshtastic/protobufs
|
||||||
|
deps: []
|
||||||
|
build:
|
||||||
|
excludes:
|
||||||
|
- node_modules
|
||||||
|
breaking:
|
||||||
|
use:
|
||||||
|
- FILE
|
||||||
|
lint:
|
||||||
|
ignore_only:
|
||||||
|
PACKAGE_DEFINED:
|
||||||
|
- nanopb.proto
|
||||||
|
use:
|
||||||
|
- MINIMAL
|
||||||
@@ -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"]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
*ChannelSet.settings max_count:8
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
* <status battery='100' />
|
||||||
|
*/
|
||||||
|
message Status {
|
||||||
|
/*
|
||||||
|
* Battery level
|
||||||
|
*/
|
||||||
|
uint32 battery = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ATAK Contact
|
||||||
|
* <contact endpoint='0.0.0.0:4242:tcp' phone='+12345678' callsign='FALKE'/>
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
*CannedMessageModuleConfig.messages max_size:201
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
|||||||
|
*WifiConnectionStatus.ssid max_size:33
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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 = "<vector>";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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<meshtastic_NodeInfoLite>"];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
*InterdeviceMessage.nmea max_size:1024
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
*RTTTLConfig.ringtone max_size:231
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
*StoreAndForward.text max_size:233
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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 <jpa@kapsi.fi>
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|
||||||
|

|
||||||
@@ -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"]
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+384
@@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user