mirror of
https://github.com/meshtastic/python.git
synced 2025-12-30 11:27:53 -05:00
Compare commits
227 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5159f1156 | ||
|
|
593b05dbcd | ||
|
|
f519d1f2d2 | ||
|
|
8b36561406 | ||
|
|
e2b4948d45 | ||
|
|
7e3d347b63 | ||
|
|
c6efccdbd2 | ||
|
|
2b10459db0 | ||
|
|
d53ced216c | ||
|
|
f5ecd28705 | ||
|
|
82ad9b2f51 | ||
|
|
03aaa4c98e | ||
|
|
d7d9c7219a | ||
|
|
c60b5d4b05 | ||
|
|
83d82c518a | ||
|
|
8a95ce4636 | ||
|
|
0261313fc5 | ||
|
|
c1a6234694 | ||
|
|
66e32f812a | ||
|
|
eb85439000 | ||
|
|
885eb4898d | ||
|
|
172c123990 | ||
|
|
fcdd83838b | ||
|
|
58967e1d91 | ||
|
|
17f7e8e20e | ||
|
|
9b5a889676 | ||
|
|
ce7c61861f | ||
|
|
4adcbb6787 | ||
|
|
125f63419e | ||
|
|
cad5d18aff | ||
|
|
706d0649c1 | ||
|
|
167044907d | ||
|
|
ab1669994f | ||
|
|
6f67f33378 | ||
|
|
e60c8ea105 | ||
|
|
d633f8c895 | ||
|
|
ca82e1ce2b | ||
|
|
0ae23eec7e | ||
|
|
2fa85bac1f | ||
|
|
58fc614fb7 | ||
|
|
795b652069 | ||
|
|
213faa0cae | ||
|
|
68a2009e0e | ||
|
|
c76e4dac87 | ||
|
|
428be9fbce | ||
|
|
d83f7b2307 | ||
|
|
eb453a2e8a | ||
|
|
308ac93399 | ||
|
|
84417f0bb1 | ||
|
|
0bb3389b3b | ||
|
|
22b3062151 | ||
|
|
373b8a3139 | ||
|
|
db21942244 | ||
|
|
c55f1ef610 | ||
|
|
51b543ff40 | ||
|
|
8752a0de6e | ||
|
|
7160e79fbf | ||
|
|
b73fcbff88 | ||
|
|
1b5b07e752 | ||
|
|
ab997aac84 | ||
|
|
a097161dbc | ||
|
|
e6750507c8 | ||
|
|
0deb98b4c6 | ||
|
|
04a0ff6322 | ||
|
|
b4764d3bc3 | ||
|
|
9281c4a335 | ||
|
|
3c2dd6f4ff | ||
|
|
8e48d141c8 | ||
|
|
8a6ee5fb35 | ||
|
|
aa786c7ebd | ||
|
|
23be2d2189 | ||
|
|
622a435465 | ||
|
|
56680f8da6 | ||
|
|
321a960c13 | ||
|
|
4668852b0b | ||
|
|
c3973117c8 | ||
|
|
d456e4ce30 | ||
|
|
ec78f62992 | ||
|
|
dfc9547ffc | ||
|
|
ee0f73a20e | ||
|
|
2e73fe310c | ||
|
|
d4bc39153a | ||
|
|
2e8f823431 | ||
|
|
675169167c | ||
|
|
75f8e27799 | ||
|
|
f426699d2b | ||
|
|
bc1664dade | ||
|
|
32a61b0209 | ||
|
|
0c38a9eb0b | ||
|
|
e591cc184f | ||
|
|
b42d33824a | ||
|
|
ed908fc4b6 | ||
|
|
3710e6e909 | ||
|
|
faa8064ccc | ||
|
|
2f44351945 | ||
|
|
f5fa30cb22 | ||
|
|
46a8db286c | ||
|
|
852949575b | ||
|
|
e2c9c1315e | ||
|
|
f41ef042a9 | ||
|
|
84bec5a7c4 | ||
|
|
985366c812 | ||
|
|
3954fbd404 | ||
|
|
5f174b2850 | ||
|
|
23ea19c00b | ||
|
|
acc47146c9 | ||
|
|
dd8803793d | ||
|
|
68ec588804 | ||
|
|
2f48594dc3 | ||
|
|
c7c3c69fc3 | ||
|
|
53e40d5aab | ||
|
|
dd3da6a670 | ||
|
|
e500b399f4 | ||
|
|
27ac28e300 | ||
|
|
6bc5f5e305 | ||
|
|
c844e4e0fe | ||
|
|
060df86bb6 | ||
|
|
7d87d5037e | ||
|
|
4ec7698d94 | ||
|
|
7cc65aa08a | ||
|
|
cc411ce0bb | ||
|
|
edff956f9d | ||
|
|
bd68739158 | ||
|
|
530d92ead2 | ||
|
|
60f9dc6266 | ||
|
|
f9ae021e43 | ||
|
|
317d81c983 | ||
|
|
5837bd0172 | ||
|
|
5487f7a791 | ||
|
|
c6d8a540eb | ||
|
|
0962c9b058 | ||
|
|
4f98602ac2 | ||
|
|
6ebddb67c0 | ||
|
|
82554a1f18 | ||
|
|
8c115dc636 | ||
|
|
e2fe359527 | ||
|
|
5600ce92b0 | ||
|
|
efb848adf9 | ||
|
|
0d8646189f | ||
|
|
d0023df8ca | ||
|
|
b522abf33e | ||
|
|
c086b6372e | ||
|
|
6ec506fe3b | ||
|
|
fc3b81dfde | ||
|
|
9c53ea017c | ||
|
|
1e6625d062 | ||
|
|
0487ce5e1a | ||
|
|
aac19b2ecc | ||
|
|
0fb72b8ad1 | ||
|
|
872fbef5d6 | ||
|
|
ec4fbe3a59 | ||
|
|
6bab385380 | ||
|
|
b8178d513a | ||
|
|
f4c085fc50 | ||
|
|
57f0598082 | ||
|
|
55d3188408 | ||
|
|
7b64fbb71b | ||
|
|
7f85eb0285 | ||
|
|
d05ef17ab3 | ||
|
|
d161291ca4 | ||
|
|
4e267c75b0 | ||
|
|
f56b9eefa6 | ||
|
|
2de1f1921c | ||
|
|
227507780e | ||
|
|
9f286c9023 | ||
|
|
0b1545393e | ||
|
|
245a9e40b1 | ||
|
|
749c6a70bc | ||
|
|
afd071c24e | ||
|
|
29f355bd61 | ||
|
|
4b6d7a8587 | ||
|
|
7cc18e9df6 | ||
|
|
a765bccf4d | ||
|
|
f950ecae2d | ||
|
|
7c7170a5dd | ||
|
|
df191e149b | ||
|
|
843abe587f | ||
|
|
ff7dcc3afb | ||
|
|
d66b8fa9dd | ||
|
|
f6f8ccfcbc | ||
|
|
cace959ca4 | ||
|
|
01ffd83d64 | ||
|
|
9284a848f2 | ||
|
|
18ac0d6d5c | ||
|
|
7c89e231bd | ||
|
|
4673824236 | ||
|
|
d87eddfd33 | ||
|
|
31f322f1c2 | ||
|
|
89b41c1a19 | ||
|
|
1a5ca789c2 | ||
|
|
74c911cb75 | ||
|
|
579383cd5a | ||
|
|
03ac322583 | ||
|
|
c63814358a | ||
|
|
663fabce74 | ||
|
|
6243965044 | ||
|
|
b180b6fb15 | ||
|
|
7bb8e4e9dd | ||
|
|
4c7ac60be6 | ||
|
|
0b086d10f8 | ||
|
|
426795fccd | ||
|
|
fb88ee114c | ||
|
|
a4630b53eb | ||
|
|
646aa981d5 | ||
|
|
9381acd6ac | ||
|
|
384063db19 | ||
|
|
20d75d9023 | ||
|
|
0deb1d788f | ||
|
|
1070d9202b | ||
|
|
b90de8b73b | ||
|
|
2e79ecf759 | ||
|
|
578d3e4b24 | ||
|
|
4ca13bcede | ||
|
|
6ceae7c72f | ||
|
|
4c29d7dd0f | ||
|
|
839bbbcad2 | ||
|
|
1abb9fb213 | ||
|
|
7fcbbe9b80 | ||
|
|
073274cb00 | ||
|
|
92a3986a8f | ||
|
|
e335f12a3b | ||
|
|
0da405168f | ||
|
|
58d9039a04 | ||
|
|
f77e788aa8 | ||
|
|
aba381fb54 | ||
|
|
60de9dddb1 | ||
|
|
a29ee840f2 |
22
.github/CONTRIBUTING.md
vendored
Normal file
22
.github/CONTRIBUTING.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Contributing to Meshtastic Python
|
||||||
|
|
||||||
|
## Development resources
|
||||||
|
- [API Documentation](https://python.meshtastic.org/)
|
||||||
|
- [Meshtastic Python Development](https://meshtastic.org/docs/development/python/)
|
||||||
|
- [Building Meshtastic Python](https://meshtastic.org/docs/development/python/building/)
|
||||||
|
- [Using the Meshtastic Python Library](https://meshtastic.org/docs/development/python/library/)
|
||||||
|
|
||||||
|
## How to check your code (pytest/pylint) before a PR
|
||||||
|
- [Pre-requisites](https://meshtastic.org/docs/development/python/building/#pre-requisites)
|
||||||
|
- also execute `poetry install --all-extras --with dev,powermon` for all optional dependencies
|
||||||
|
- check your code with github ci actions locally
|
||||||
|
- You need to have act installed. You can get it at https://nektosact.com/
|
||||||
|
- on linux: `act -P ubuntu-latest=-self-hosted --matrix "python-version:3.12"`
|
||||||
|
- on windows:
|
||||||
|
- linux checks (linux docker): `act --matrix "python-version:3.12"`
|
||||||
|
- windows checks (windows host): `act -P ubuntu-latest=-self-hosted --matrix "python-version:3.12"`
|
||||||
|
- or run all locally:
|
||||||
|
- run `poetry run pylint meshtastic examples/ --ignore-patterns ".*_pb2.pyi?$"`
|
||||||
|
- run `poetry run mypy meshtastic/`
|
||||||
|
- run `poetry run pytest`
|
||||||
|
- more commands see [CI workflow](https://github.com/meshtastic/python/blob/master/.github/workflows/ci.yml)
|
||||||
BIN
.github/meshtastic_logo.png
vendored
Normal file
BIN
.github/meshtastic_logo.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 105 KiB |
27
.vscode/launch.json
vendored
27
.vscode/launch.json
vendored
@@ -4,6 +4,7 @@
|
|||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
|
|
||||||
{
|
{
|
||||||
"name": "meshtastic BLE",
|
"name": "meshtastic BLE",
|
||||||
"type": "debugpy",
|
"type": "debugpy",
|
||||||
@@ -245,6 +246,30 @@
|
|||||||
"module": "meshtastic",
|
"module": "meshtastic",
|
||||||
"justMyCode": true,
|
"justMyCode": true,
|
||||||
"args": ["--debug", "--nodes"]
|
"args": ["--debug", "--nodes"]
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
"name": "meshtastic nodes table",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "launch",
|
||||||
|
"module": "meshtastic",
|
||||||
|
"justMyCode": true,
|
||||||
|
"args": ["--nodes"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "meshtastic nodes table with show-fields",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "launch",
|
||||||
|
"module": "meshtastic",
|
||||||
|
"justMyCode": true,
|
||||||
|
"args": ["--nodes", "--show-fields", "AKA,Pubkey,Role,Role,Role,Latitude,Latitude,deviceMetrics.voltage"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "meshtastic --export-config",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "launch",
|
||||||
|
"module": "meshtastic",
|
||||||
|
"justMyCode": true,
|
||||||
|
"args": ["--export-config", "config.json"]
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
21
README.md
21
README.md
@@ -1,4 +1,10 @@
|
|||||||
# Meshtastic Python
|
<div align="center" markdown="1">
|
||||||
|
|
||||||
|
<img src=".github/meshtastic_logo.png" alt="Meshtastic Logo" width="80"/>
|
||||||
|
|
||||||
|
<h1 align="center"> Meshtastic Python
|
||||||
|
</h1>
|
||||||
|
<p style="font-size:15px;" align="center">A Python library and client for use with Meshtastic devices. </p>
|
||||||
|
|
||||||
[](https://codecov.io/gh/meshtastic/python)
|
[](https://codecov.io/gh/meshtastic/python)
|
||||||

|

|
||||||
@@ -7,17 +13,20 @@
|
|||||||
[](https://opencollective.com/meshtastic/)
|
[](https://opencollective.com/meshtastic/)
|
||||||

|

|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a href="https://meshtastic.org/docs/software/python/cli/installation">Getting Started Guide</a>
|
||||||
|
-
|
||||||
|
<a href="https://python.meshtastic.org">API Documentation</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
A Python client for use with Meshtastic devices.
|
|
||||||
This small library (and example application) provides an easy API for sending and receiving messages over mesh radios.
|
This small library (and example application) provides an easy API for sending and receiving messages over mesh radios.
|
||||||
It also provides access to any of the operations/data available in the device user interface or the Android application.
|
It also provides access to any of the operations/data available in the device user interface or the Android application.
|
||||||
Events are delivered using a publish-subscribe model, and you can subscribe to only the message types you are interested in.
|
Events are delivered using a publish-subscribe model, and you can subscribe to only the message types you are interested in.
|
||||||
|
|
||||||
**[Getting Started Guide](https://meshtastic.org/docs/software/python/cli/installation)**
|
|
||||||
|
|
||||||
(Documentation/API Reference is currently offline)
|
|
||||||
|
|
||||||
## Call for Contributors
|
## Call for Contributors
|
||||||
|
|
||||||
This library and CLI has gone without a consistent maintainer for a while, and there's many improvements that could be made. We're all volunteers here and help is extremely appreciated, whether in implementing your own needs or helping maintain the library and CLI in general.
|
This library and CLI has gone without a consistent maintainer for a while, and there's many improvements that could be made. We're all volunteers here and help is extremely appreciated, whether in implementing your own needs or helping maintain the library and CLI in general.
|
||||||
|
|||||||
@@ -6,6 +6,12 @@ set -e
|
|||||||
#gsed -i 's/import "\//import ".\//g' ./protobufs/meshtastic/*
|
#gsed -i 's/import "\//import ".\//g' ./protobufs/meshtastic/*
|
||||||
#gsed -i 's/package meshtastic;//g' ./protobufs/meshtastic/*
|
#gsed -i 's/package meshtastic;//g' ./protobufs/meshtastic/*
|
||||||
|
|
||||||
|
POETRYDIR=$(poetry env info --path)
|
||||||
|
|
||||||
|
if [[ -z "${POETRYDIR}" ]]; then
|
||||||
|
poetry install
|
||||||
|
fi
|
||||||
|
|
||||||
# protoc looks for mypy plugin in the python path
|
# protoc looks for mypy plugin in the python path
|
||||||
source $(poetry env info --path)/bin/activate
|
source $(poetry env info --path)/bin/activate
|
||||||
|
|
||||||
@@ -22,6 +28,7 @@ OUTDIR=${TMPDIR}/out
|
|||||||
PYIDIR=${TMPDIR}/out
|
PYIDIR=${TMPDIR}/out
|
||||||
mkdir -p "${OUTDIR}" "${INDIR}" "${PYIDIR}"
|
mkdir -p "${OUTDIR}" "${INDIR}" "${PYIDIR}"
|
||||||
cp ./protobufs/meshtastic/*.proto "${INDIR}"
|
cp ./protobufs/meshtastic/*.proto "${INDIR}"
|
||||||
|
cp ./protobufs/nanopb.proto "${INDIR}"
|
||||||
|
|
||||||
# OS-X sed is apparently a little different and expects an arg for -i
|
# OS-X sed is apparently a little different and expects an arg for -i
|
||||||
if [[ $OSTYPE == 'darwin'* ]]; then
|
if [[ $OSTYPE == 'darwin'* ]]; then
|
||||||
@@ -36,6 +43,8 @@ $SEDCMD 's/^package meshtastic;/package meshtastic.protobuf;/' "${INDIR}/"*.prot
|
|||||||
# fix the imports to match
|
# fix the imports to match
|
||||||
$SEDCMD 's/^import "meshtastic\//import "meshtastic\/protobuf\//' "${INDIR}/"*.proto
|
$SEDCMD 's/^import "meshtastic\//import "meshtastic\/protobuf\//' "${INDIR}/"*.proto
|
||||||
|
|
||||||
|
$SEDCMD 's/^import "nanopb.proto"/import "meshtastic\/protobuf\/nanopb.proto"/' "${INDIR}/"*.proto
|
||||||
|
|
||||||
# Generate the python files
|
# Generate the python files
|
||||||
./nanopb-0.4.8/generator-bin/protoc -I=$TMPDIR/in --python_out "${OUTDIR}" "--mypy_out=${PYIDIR}" $INDIR/*.proto
|
./nanopb-0.4.8/generator-bin/protoc -I=$TMPDIR/in --python_out "${OUTDIR}" "--mypy_out=${PYIDIR}" $INDIR/*.proto
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ owner_short: BOB
|
|||||||
|
|
||||||
channel_url: https://www.meshtastic.org/e/#CgMSAQESCDgBQANIAVAe
|
channel_url: https://www.meshtastic.org/e/#CgMSAQESCDgBQANIAVAe
|
||||||
|
|
||||||
|
canned_messages: Hi|Bye|Yes|No|Ok
|
||||||
|
ringtone: 24:d=32,o=5,b=565:f6,p,f6,4p,p,f6,p,f6,2p,p,b6,p,b6,p,b6,p,b6,p,b,p,b,p,b,p,b,p,b,p,b,p,b,p,b,1p.,2p.,p
|
||||||
|
|
||||||
location:
|
location:
|
||||||
lat: 35.88888
|
lat: 35.88888
|
||||||
lon: -93.88888
|
lon: -93.88888
|
||||||
|
|||||||
55
examples/waypoint.py
Normal file
55
examples/waypoint.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
"""Program to create and delete waypoint
|
||||||
|
To run:
|
||||||
|
python3 examples/waypoint.py --port /dev/ttyUSB0 create 45 test the_desc_2 '2024-12-18T23:05:23' 48.74 7.35
|
||||||
|
python3 examples/waypoint.py delete 45
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import datetime
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import meshtastic
|
||||||
|
import meshtastic.serial_interface
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
prog='waypoint',
|
||||||
|
description='Create and delete Meshtastic waypoint')
|
||||||
|
parser.add_argument('--port', default=None)
|
||||||
|
parser.add_argument('--debug', default=False, action='store_true')
|
||||||
|
|
||||||
|
subparsers = parser.add_subparsers(dest='cmd')
|
||||||
|
parser_delete = subparsers.add_parser('delete', help='Delete a waypoint')
|
||||||
|
parser_delete.add_argument('id', help="id of the waypoint")
|
||||||
|
|
||||||
|
parser_create = subparsers.add_parser('create', help='Create a new waypoint')
|
||||||
|
parser_create.add_argument('id', help="id of the waypoint")
|
||||||
|
parser_create.add_argument('name', help="name of the waypoint")
|
||||||
|
parser_create.add_argument('description', help="description of the waypoint")
|
||||||
|
parser_create.add_argument('expire', help="expiration date of the waypoint as interpreted by datetime.fromisoformat")
|
||||||
|
parser_create.add_argument('latitude', help="latitude of the waypoint")
|
||||||
|
parser_create.add_argument('longitude', help="longitude of the waypoint")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
print(args)
|
||||||
|
|
||||||
|
# By default will try to find a meshtastic device,
|
||||||
|
# otherwise provide a device path like /dev/ttyUSB0
|
||||||
|
if args.debug:
|
||||||
|
d = sys.stderr
|
||||||
|
else:
|
||||||
|
d = None
|
||||||
|
with meshtastic.serial_interface.SerialInterface(args.port, debugOut=d) as iface:
|
||||||
|
if args.cmd == 'create':
|
||||||
|
p = iface.sendWaypoint(
|
||||||
|
waypoint_id=int(args.id),
|
||||||
|
name=args.name,
|
||||||
|
description=args.description,
|
||||||
|
expire=int(datetime.datetime.fromisoformat(args.expire).timestamp()),
|
||||||
|
latitude=float(args.latitude),
|
||||||
|
longitude=float(args.longitude),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
p = iface.deleteWaypoint(int(args.id))
|
||||||
|
print(p)
|
||||||
|
|
||||||
|
# iface.close()
|
||||||
@@ -35,6 +35,7 @@ type of packet, you should subscribe to the full topic name. If you want to see
|
|||||||
- `meshtastic.receive.data.portnum(packet)` (where portnum is an integer or well known PortNum enum)
|
- `meshtastic.receive.data.portnum(packet)` (where portnum is an integer or well known PortNum enum)
|
||||||
- `meshtastic.node.updated(node = NodeInfo)` - published when a node in the DB changes (appears, location changed, username changed, etc...)
|
- `meshtastic.node.updated(node = NodeInfo)` - published when a node in the DB changes (appears, location changed, username changed, etc...)
|
||||||
- `meshtastic.log.line(line)` - a raw unparsed log line from the radio
|
- `meshtastic.log.line(line)` - a raw unparsed log line from the radio
|
||||||
|
- `meshtastic.clientNotification(notification, interface) - a ClientNotification sent from the radio
|
||||||
|
|
||||||
We receive position, user, or data packets from the mesh. You probably only care about `meshtastic.receive.data`. The first argument for
|
We receive position, user, or data packets from the mesh. You probably only care about `meshtastic.receive.data`. The first argument for
|
||||||
that publish will be the packet. Text or binary data packets (from `sendData` or `sendText`) will both arrive this way. If you print packet
|
that publish will be the packet. Text or binary data packets (from `sendData` or `sendText`) will both arrive this way. If you print packet
|
||||||
@@ -80,7 +81,6 @@ from typing import *
|
|||||||
|
|
||||||
import google.protobuf.json_format
|
import google.protobuf.json_format
|
||||||
import serial # type: ignore[import-untyped]
|
import serial # type: ignore[import-untyped]
|
||||||
from dotmap import DotMap # type: ignore[import-untyped]
|
|
||||||
from google.protobuf.json_format import MessageToJson
|
from google.protobuf.json_format import MessageToJson
|
||||||
from pubsub import pub # type: ignore[import-untyped]
|
from pubsub import pub # type: ignore[import-untyped]
|
||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
@@ -111,13 +111,13 @@ from . import (
|
|||||||
LOCAL_ADDR = "^local"
|
LOCAL_ADDR = "^local"
|
||||||
"""A special ID that means the local node"""
|
"""A special ID that means the local node"""
|
||||||
|
|
||||||
BROADCAST_NUM = 0xFFFFFFFF
|
BROADCAST_NUM: int = 0xFFFFFFFF
|
||||||
"""if using 8 bit nodenums this will be shortened on the target"""
|
"""if using 8 bit nodenums this will be shortened on the target"""
|
||||||
|
|
||||||
BROADCAST_ADDR = "^all"
|
BROADCAST_ADDR = "^all"
|
||||||
"""A special ID that means broadcast"""
|
"""A special ID that means broadcast"""
|
||||||
|
|
||||||
OUR_APP_VERSION = 20300
|
OUR_APP_VERSION: int = 20300
|
||||||
"""The numeric buildnumber (shared with android apps) specifying the
|
"""The numeric buildnumber (shared with android apps) specifying the
|
||||||
level of device code we are guaranteed to understand
|
level of device code we are guaranteed to understand
|
||||||
|
|
||||||
@@ -134,7 +134,9 @@ class ResponseHandler(NamedTuple):
|
|||||||
"""A pending response callback, waiting for a response to one of our messages"""
|
"""A pending response callback, waiting for a response to one of our messages"""
|
||||||
|
|
||||||
# requestId: int - used only as a key
|
# requestId: int - used only as a key
|
||||||
|
#: a callable to call when a response is received
|
||||||
callback: Callable
|
callback: Callable
|
||||||
|
#: Whether ACKs and NAKs should be passed to this handler
|
||||||
ackPermitted: bool = False
|
ackPermitted: bool = False
|
||||||
# FIXME, add timestamp and age out old requests
|
# FIXME, add timestamp and age out old requests
|
||||||
|
|
||||||
@@ -142,11 +144,11 @@ class ResponseHandler(NamedTuple):
|
|||||||
class KnownProtocol(NamedTuple):
|
class KnownProtocol(NamedTuple):
|
||||||
"""Used to automatically decode known protocol payloads"""
|
"""Used to automatically decode known protocol payloads"""
|
||||||
|
|
||||||
|
#: A descriptive name (e.g. "text", "user", "admin")
|
||||||
name: str
|
name: str
|
||||||
# portnum: int, now a key
|
#: If set, will be called to parse as a protocol buffer
|
||||||
# If set, will be called to prase as a protocol buffer
|
|
||||||
protobufFactory: Optional[Callable] = None
|
protobufFactory: Optional[Callable] = None
|
||||||
# If set, invoked as onReceive(interface, packet)
|
#: If set, invoked as onReceive(interface, packet)
|
||||||
onReceive: Optional[Callable] = None
|
onReceive: Optional[Callable] = None
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,23 +3,43 @@
|
|||||||
|
|
||||||
# We just hit the 1600 line limit for main.py, but I currently have a huge set of powermon/structured logging changes
|
# We just hit the 1600 line limit for main.py, but I currently have a huge set of powermon/structured logging changes
|
||||||
# later we can have a separate changelist to refactor main.py into smaller files
|
# later we can have a separate changelist to refactor main.py into smaller files
|
||||||
# pylint: disable=too-many-lines
|
# pylint: disable=R0917,C0302
|
||||||
|
|
||||||
|
from typing import List, Optional, Union
|
||||||
|
from types import ModuleType
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
argcomplete: Union[None, ModuleType] = None
|
||||||
|
try:
|
||||||
|
import argcomplete # type: ignore
|
||||||
|
except ImportError as e:
|
||||||
|
pass # already set to None by default above
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
import pyqrcode # type: ignore[import-untyped]
|
try:
|
||||||
|
import pyqrcode # type: ignore[import-untyped]
|
||||||
|
except ImportError as e:
|
||||||
|
pyqrcode = None
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from google.protobuf.json_format import MessageToDict
|
from google.protobuf.json_format import MessageToDict
|
||||||
from pubsub import pub # type: ignore[import-untyped]
|
from pubsub import pub # type: ignore[import-untyped]
|
||||||
|
|
||||||
import meshtastic.test
|
try:
|
||||||
|
import meshtastic.test
|
||||||
|
have_test = True
|
||||||
|
except ImportError as e:
|
||||||
|
have_test = False
|
||||||
|
|
||||||
import meshtastic.util
|
import meshtastic.util
|
||||||
|
import meshtastic.serial_interface
|
||||||
|
import meshtastic.tcp_interface
|
||||||
|
|
||||||
from meshtastic import BROADCAST_ADDR, mt_config, remote_hardware
|
from meshtastic import BROADCAST_ADDR, mt_config, remote_hardware
|
||||||
from meshtastic.ble_interface import BLEInterface
|
from meshtastic.ble_interface import BLEInterface
|
||||||
from meshtastic.mesh_interface import MeshInterface
|
from meshtastic.mesh_interface import MeshInterface
|
||||||
@@ -39,10 +59,10 @@ except ImportError as e:
|
|||||||
have_powermon = False
|
have_powermon = False
|
||||||
powermon_exception = e
|
powermon_exception = e
|
||||||
meter = None
|
meter = None
|
||||||
from meshtastic.protobuf import channel_pb2, config_pb2, portnums_pb2
|
from meshtastic.protobuf import channel_pb2, config_pb2, portnums_pb2, mesh_pb2
|
||||||
from meshtastic.version import get_active_version
|
from meshtastic.version import get_active_version
|
||||||
|
|
||||||
def onReceive(packet, interface):
|
def onReceive(packet, interface) -> None:
|
||||||
"""Callback invoked when a packet arrives"""
|
"""Callback invoked when a packet arrives"""
|
||||||
args = mt_config.args
|
args = mt_config.args
|
||||||
try:
|
try:
|
||||||
@@ -54,7 +74,7 @@ def onReceive(packet, interface):
|
|||||||
args
|
args
|
||||||
and args.sendtext
|
and args.sendtext
|
||||||
and packet["to"] == interface.myInfo.my_node_num
|
and packet["to"] == interface.myInfo.my_node_num
|
||||||
and d["portnum"] == portnums_pb2.PortNum.TEXT_MESSAGE_APP
|
and d.get("portnum", portnums_pb2.PortNum.UNKNOWN_APP) == portnums_pb2.PortNum.TEXT_MESSAGE_APP
|
||||||
):
|
):
|
||||||
interface.close() # after running command then exit
|
interface.close() # after running command then exit
|
||||||
|
|
||||||
@@ -70,10 +90,10 @@ def onReceive(packet, interface):
|
|||||||
interface.sendText(reply)
|
interface.sendText(reply)
|
||||||
|
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print(f"Warning: There is no field {ex} in the packet.")
|
print(f"Warning: Error processing received packet: {ex}.")
|
||||||
|
|
||||||
|
|
||||||
def onConnection(interface, topic=pub.AUTO_TOPIC): # pylint: disable=W0613
|
def onConnection(interface, topic=pub.AUTO_TOPIC) -> None: # pylint: disable=W0613
|
||||||
"""Callback invoked when we connect/disconnect from a radio"""
|
"""Callback invoked when we connect/disconnect from a radio"""
|
||||||
print(f"Connection changed: {topic.getName()}")
|
print(f"Connection changed: {topic.getName()}")
|
||||||
|
|
||||||
@@ -85,8 +105,16 @@ def checkChannel(interface: MeshInterface, channelIndex: int) -> bool:
|
|||||||
return ch and ch.role != channel_pb2.Channel.Role.DISABLED
|
return ch and ch.role != channel_pb2.Channel.Role.DISABLED
|
||||||
|
|
||||||
|
|
||||||
def getPref(node, comp_name):
|
def getPref(node, comp_name) -> bool:
|
||||||
"""Get a channel or preferences value"""
|
"""Get a channel or preferences value"""
|
||||||
|
def _printSetting(config_type, uni_name, pref_value, repeated):
|
||||||
|
"""Pretty print the setting"""
|
||||||
|
if repeated:
|
||||||
|
pref_value = [meshtastic.util.toStr(v) for v in pref_value]
|
||||||
|
else:
|
||||||
|
pref_value = meshtastic.util.toStr(pref_value)
|
||||||
|
print(f"{str(config_type.name)}.{uni_name}: {str(pref_value)}")
|
||||||
|
logging.debug(f"{str(config_type.name)}.{uni_name}: {str(pref_value)}")
|
||||||
|
|
||||||
name = splitCompoundName(comp_name)
|
name = splitCompoundName(comp_name)
|
||||||
wholeField = name[0] == name[1] # We want the whole field
|
wholeField = name[0] == name[1] # We want the whole field
|
||||||
@@ -94,17 +122,18 @@ def getPref(node, comp_name):
|
|||||||
camel_name = meshtastic.util.snake_to_camel(name[1])
|
camel_name = meshtastic.util.snake_to_camel(name[1])
|
||||||
# Note: protobufs has the keys in snake_case, so snake internally
|
# Note: protobufs has the keys in snake_case, so snake internally
|
||||||
snake_name = meshtastic.util.camel_to_snake(name[1])
|
snake_name = meshtastic.util.camel_to_snake(name[1])
|
||||||
|
uni_name = camel_name if mt_config.camel_case else snake_name
|
||||||
logging.debug(f"snake_name:{snake_name} camel_name:{camel_name}")
|
logging.debug(f"snake_name:{snake_name} camel_name:{camel_name}")
|
||||||
logging.debug(f"use camel:{mt_config.camel_case}")
|
logging.debug(f"use camel:{mt_config.camel_case}")
|
||||||
|
|
||||||
# First validate the input
|
# First validate the input
|
||||||
localConfig = node.localConfig
|
localConfig = node.localConfig
|
||||||
moduleConfig = node.moduleConfig
|
moduleConfig = node.moduleConfig
|
||||||
found = False
|
found: bool = False
|
||||||
for config in [localConfig, moduleConfig]:
|
for config in [localConfig, moduleConfig]:
|
||||||
objDesc = config.DESCRIPTOR
|
objDesc = config.DESCRIPTOR
|
||||||
config_type = objDesc.fields_by_name.get(name[0])
|
config_type = objDesc.fields_by_name.get(name[0])
|
||||||
pref = False
|
pref = "" #FIXME - is this correct to leave as an empty string if not found?
|
||||||
if config_type:
|
if config_type:
|
||||||
pref = config_type.message_type.fields_by_name.get(snake_name)
|
pref = config_type.message_type.fields_by_name.get(snake_name)
|
||||||
if pref or wholeField:
|
if pref or wholeField:
|
||||||
@@ -112,38 +141,26 @@ def getPref(node, comp_name):
|
|||||||
break
|
break
|
||||||
|
|
||||||
if not found:
|
if not found:
|
||||||
if mt_config.camel_case:
|
print(
|
||||||
print(
|
f"{localConfig.__class__.__name__} and {moduleConfig.__class__.__name__} do not have attribute {uni_name}."
|
||||||
f"{localConfig.__class__.__name__} and {moduleConfig.__class__.__name__} do not have an attribute {snake_name}."
|
)
|
||||||
)
|
|
||||||
else:
|
|
||||||
print(
|
|
||||||
f"{localConfig.__class__.__name__} and {moduleConfig.__class__.__name__} do not have attribute {snake_name}."
|
|
||||||
)
|
|
||||||
print("Choices are...")
|
print("Choices are...")
|
||||||
printConfig(localConfig)
|
printConfig(localConfig)
|
||||||
printConfig(moduleConfig)
|
printConfig(moduleConfig)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Check if we need to request the config
|
# Check if we need to request the config
|
||||||
if len(config.ListFields()) != 0:
|
if len(config.ListFields()) != 0 and not isinstance(pref, str): # if str, it's still the empty string, I think
|
||||||
# read the value
|
# read the value
|
||||||
config_values = getattr(config, config_type.name)
|
config_values = getattr(config, config_type.name)
|
||||||
if not wholeField:
|
if not wholeField:
|
||||||
pref_value = getattr(config_values, pref.name)
|
pref_value = getattr(config_values, pref.name)
|
||||||
if mt_config.camel_case:
|
repeated = pref.label == pref.LABEL_REPEATED
|
||||||
print(f"{str(config_type.name)}.{camel_name}: {str(pref_value)}")
|
_printSetting(config_type, uni_name, pref_value, repeated)
|
||||||
logging.debug(
|
|
||||||
f"{str(config_type.name)}.{camel_name}: {str(pref_value)}"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
print(f"{str(config_type.name)}.{snake_name}: {str(pref_value)}")
|
|
||||||
logging.debug(
|
|
||||||
f"{str(config_type.name)}.{snake_name}: {str(pref_value)}"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
print(f"{str(config_type.name)}:\n{str(config_values)}")
|
for field in config_values.ListFields():
|
||||||
logging.debug(f"{str(config_type.name)}: {str(config_values)}")
|
repeated = field[0].label == field[0].LABEL_REPEATED
|
||||||
|
_printSetting(config_type, field[0].name, field[1], repeated)
|
||||||
else:
|
else:
|
||||||
# Always show whole field for remote node
|
# Always show whole field for remote node
|
||||||
node.requestConfig(config_type)
|
node.requestConfig(config_type)
|
||||||
@@ -151,16 +168,16 @@ def getPref(node, comp_name):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def splitCompoundName(comp_name):
|
def splitCompoundName(comp_name: str) -> List[str]:
|
||||||
"""Split compound (dot separated) preference name into parts"""
|
"""Split compound (dot separated) preference name into parts"""
|
||||||
name = comp_name.split(".")
|
name: List[str] = comp_name.split(".")
|
||||||
if len(name) < 2:
|
if len(name) < 2:
|
||||||
name[0] = comp_name
|
name[0] = comp_name
|
||||||
name.append(comp_name)
|
name.append(comp_name)
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
|
||||||
def traverseConfig(config_root, config, interface_config):
|
def traverseConfig(config_root, config, interface_config) -> bool:
|
||||||
"""Iterate through current config level preferences and either traverse deeper if preference is a dict or set preference"""
|
"""Iterate through current config level preferences and either traverse deeper if preference is a dict or set preference"""
|
||||||
snake_name = meshtastic.util.camel_to_snake(config_root)
|
snake_name = meshtastic.util.camel_to_snake(config_root)
|
||||||
for pref in config:
|
for pref in config:
|
||||||
@@ -168,18 +185,19 @@ def traverseConfig(config_root, config, interface_config):
|
|||||||
if isinstance(config[pref], dict):
|
if isinstance(config[pref], dict):
|
||||||
traverseConfig(pref_name, config[pref], interface_config)
|
traverseConfig(pref_name, config[pref], interface_config)
|
||||||
else:
|
else:
|
||||||
setPref(interface_config, pref_name, str(config[pref]))
|
setPref(interface_config, pref_name, config[pref])
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def setPref(config, comp_name, valStr) -> bool:
|
def setPref(config, comp_name, raw_val) -> bool:
|
||||||
"""Set a channel or preferences value"""
|
"""Set a channel or preferences value"""
|
||||||
|
|
||||||
name = splitCompoundName(comp_name)
|
name = splitCompoundName(comp_name)
|
||||||
|
|
||||||
snake_name = meshtastic.util.camel_to_snake(name[-1])
|
snake_name = meshtastic.util.camel_to_snake(name[-1])
|
||||||
camel_name = meshtastic.util.snake_to_camel(name[-1])
|
camel_name = meshtastic.util.snake_to_camel(name[-1])
|
||||||
|
uni_name = camel_name if mt_config.camel_case else snake_name
|
||||||
logging.debug(f"snake_name:{snake_name}")
|
logging.debug(f"snake_name:{snake_name}")
|
||||||
logging.debug(f"camel_name:{camel_name}")
|
logging.debug(f"camel_name:{camel_name}")
|
||||||
|
|
||||||
@@ -201,11 +219,14 @@ def setPref(config, comp_name, valStr) -> bool:
|
|||||||
if (not pref) or (not config_type):
|
if (not pref) or (not config_type):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
val = meshtastic.util.fromStr(valStr)
|
if isinstance(raw_val, str):
|
||||||
logging.debug(f"valStr:{valStr} val:{val}")
|
val = meshtastic.util.fromStr(raw_val)
|
||||||
|
else:
|
||||||
|
val = raw_val
|
||||||
|
logging.debug(f"valStr:{raw_val} val:{val}")
|
||||||
|
|
||||||
if snake_name == "wifi_psk" and len(valStr) < 8:
|
if snake_name == "wifi_psk" and len(str(raw_val)) < 8:
|
||||||
print(f"Warning: network.wifi_psk must be 8 or more characters.")
|
print("Warning: network.wifi_psk must be 8 or more characters.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
enumType = pref.enum_type
|
enumType = pref.enum_type
|
||||||
@@ -216,14 +237,9 @@ def setPref(config, comp_name, valStr) -> bool:
|
|||||||
if e:
|
if e:
|
||||||
val = e.number
|
val = e.number
|
||||||
else:
|
else:
|
||||||
if mt_config.camel_case:
|
print(
|
||||||
print(
|
f"{name[0]}.{uni_name} does not have an enum called {val}, so you can not set it."
|
||||||
f"{name[0]}.{camel_name} does not have an enum called {val}, so you can not set it."
|
)
|
||||||
)
|
|
||||||
else:
|
|
||||||
print(
|
|
||||||
f"{name[0]}.{snake_name} does not have an enum called {val}, so you can not set it."
|
|
||||||
)
|
|
||||||
print(f"Choices in sorted order are:")
|
print(f"Choices in sorted order are:")
|
||||||
names = []
|
names = []
|
||||||
for f in enumType.values:
|
for f in enumType.values:
|
||||||
@@ -244,7 +260,11 @@ def setPref(config, comp_name, valStr) -> bool:
|
|||||||
except TypeError:
|
except TypeError:
|
||||||
# The setter didn't like our arg type guess try again as a string
|
# The setter didn't like our arg type guess try again as a string
|
||||||
config_values = getattr(config_part, config_type.name)
|
config_values = getattr(config_part, config_type.name)
|
||||||
setattr(config_values, pref.name, valStr)
|
setattr(config_values, pref.name, str(val))
|
||||||
|
elif type(val) == list:
|
||||||
|
new_vals = [meshtastic.util.fromStr(x) for x in val]
|
||||||
|
config_values = getattr(config, config_type.name)
|
||||||
|
getattr(config_values, pref.name)[:] = new_vals
|
||||||
else:
|
else:
|
||||||
config_values = getattr(config, config_type.name)
|
config_values = getattr(config, config_type.name)
|
||||||
if val == 0:
|
if val == 0:
|
||||||
@@ -252,16 +272,14 @@ def setPref(config, comp_name, valStr) -> bool:
|
|||||||
print(f"Clearing {pref.name} list")
|
print(f"Clearing {pref.name} list")
|
||||||
del getattr(config_values, pref.name)[:]
|
del getattr(config_values, pref.name)[:]
|
||||||
else:
|
else:
|
||||||
print(f"Adding '{val}' to the {pref.name} list")
|
print(f"Adding '{raw_val}' to the {pref.name} list")
|
||||||
cur_vals = [x for x in getattr(config_values, pref.name) if x not in [0, "", b""]]
|
cur_vals = [x for x in getattr(config_values, pref.name) if x not in [0, "", b""]]
|
||||||
cur_vals.append(val)
|
cur_vals.append(val)
|
||||||
getattr(config_values, pref.name)[:] = cur_vals
|
getattr(config_values, pref.name)[:] = cur_vals
|
||||||
|
return True
|
||||||
|
|
||||||
prefix = f"{'.'.join(name[0:-1])}." if config_type.message_type is not None else ""
|
prefix = f"{'.'.join(name[0:-1])}." if config_type.message_type is not None else ""
|
||||||
if mt_config.camel_case:
|
print(f"Set {prefix}{uni_name} to {raw_val}")
|
||||||
print(f"Set {prefix}{camel_name} to {valStr}")
|
|
||||||
else:
|
|
||||||
print(f"Set {prefix}{snake_name} to {valStr}")
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -321,32 +339,60 @@ def onConnected(interface):
|
|||||||
# can include lat/long/alt etc: latitude = 37.5, longitude = -122.1
|
# can include lat/long/alt etc: latitude = 37.5, longitude = -122.1
|
||||||
interface.getNode(args.dest, False, **getNode_kwargs).setFixedPosition(lat, lon, alt)
|
interface.getNode(args.dest, False, **getNode_kwargs).setFixedPosition(lat, lon, alt)
|
||||||
|
|
||||||
if args.set_owner or args.set_owner_short:
|
if args.set_owner or args.set_owner_short or args.set_is_unmessageable:
|
||||||
closeNow = True
|
closeNow = True
|
||||||
waitForAckNak = True
|
waitForAckNak = True
|
||||||
if args.set_owner and args.set_owner_short:
|
|
||||||
print(f"Setting device owner to {args.set_owner} and short name to {args.set_owner_short}")
|
|
||||||
elif args.set_owner:
|
|
||||||
print(f"Setting device owner to {args.set_owner}")
|
|
||||||
else: # short name only
|
|
||||||
print(f"Setting device owner short to {args.set_owner_short}")
|
|
||||||
interface.getNode(args.dest, False, **getNode_kwargs).setOwner(long_name=args.set_owner, short_name=args.set_owner_short)
|
|
||||||
|
|
||||||
# TODO: add to export-config and configure
|
long_name = args.set_owner.strip() if args.set_owner else None
|
||||||
|
short_name = args.set_owner_short.strip() if args.set_owner_short else None
|
||||||
|
|
||||||
|
if long_name is not None and not long_name:
|
||||||
|
meshtastic.util.our_exit("ERROR: Long Name cannot be empty or contain only whitespace characters")
|
||||||
|
|
||||||
|
if short_name is not None and not short_name:
|
||||||
|
meshtastic.util.our_exit("ERROR: Short Name cannot be empty or contain only whitespace characters")
|
||||||
|
|
||||||
|
if long_name and short_name:
|
||||||
|
print(f"Setting device owner to {long_name} and short name to {short_name}")
|
||||||
|
elif long_name:
|
||||||
|
print(f"Setting device owner to {long_name}")
|
||||||
|
elif short_name:
|
||||||
|
print(f"Setting device owner short to {short_name}")
|
||||||
|
|
||||||
|
unmessagable = None
|
||||||
|
if args.set_is_unmessageable is not None:
|
||||||
|
unmessagable = (
|
||||||
|
meshtastic.util.fromStr(args.set_is_unmessageable)
|
||||||
|
if isinstance(args.set_is_unmessageable, str)
|
||||||
|
else args.set_is_unmessageable
|
||||||
|
)
|
||||||
|
print(f"Setting device owner is_unmessageable to {unmessagable}")
|
||||||
|
|
||||||
|
interface.getNode(args.dest, False, **getNode_kwargs).setOwner(
|
||||||
|
long_name=long_name,
|
||||||
|
short_name=short_name,
|
||||||
|
is_unmessagable=unmessagable
|
||||||
|
)
|
||||||
|
|
||||||
if args.set_canned_message:
|
if args.set_canned_message:
|
||||||
closeNow = True
|
closeNow = True
|
||||||
waitForAckNak = True
|
waitForAckNak = True
|
||||||
print(f"Setting canned plugin message to {args.set_canned_message}")
|
node = interface.getNode(args.dest, False, **getNode_kwargs)
|
||||||
interface.getNode(args.dest, False, **getNode_kwargs).set_canned_message(
|
if node.module_available(mesh_pb2.CANNEDMSG_CONFIG):
|
||||||
args.set_canned_message
|
print(f"Setting canned plugin message to {args.set_canned_message}")
|
||||||
)
|
node.set_canned_message(args.set_canned_message)
|
||||||
|
else:
|
||||||
|
print("Canned Message module is excluded by firmware; skipping set.")
|
||||||
|
|
||||||
# TODO: add to export-config and configure
|
|
||||||
if args.set_ringtone:
|
if args.set_ringtone:
|
||||||
closeNow = True
|
closeNow = True
|
||||||
waitForAckNak = True
|
waitForAckNak = True
|
||||||
print(f"Setting ringtone to {args.set_ringtone}")
|
node = interface.getNode(args.dest, False, **getNode_kwargs)
|
||||||
interface.getNode(args.dest, False, **getNode_kwargs).set_ringtone(args.set_ringtone)
|
if node.module_available(mesh_pb2.EXTNOTIF_CONFIG):
|
||||||
|
print(f"Setting ringtone to {args.set_ringtone}")
|
||||||
|
node.set_ringtone(args.set_ringtone)
|
||||||
|
else:
|
||||||
|
print("External Notification is excluded by firmware; skipping ringtone set.")
|
||||||
|
|
||||||
if args.pos_fields:
|
if args.pos_fields:
|
||||||
# If --pos-fields invoked with args, set position fields
|
# If --pos-fields invoked with args, set position fields
|
||||||
@@ -384,6 +430,8 @@ def onConnected(interface):
|
|||||||
print(" ".join(fieldNames))
|
print(" ".join(fieldNames))
|
||||||
|
|
||||||
if args.set_ham:
|
if args.set_ham:
|
||||||
|
if not args.set_ham.strip():
|
||||||
|
meshtastic.util.our_exit("ERROR: Ham radio callsign cannot be empty or contain only whitespace characters")
|
||||||
closeNow = True
|
closeNow = True
|
||||||
print(f"Setting Ham ID to {args.set_ham} and turning off encryption")
|
print(f"Setting Ham ID to {args.set_ham} and turning off encryption")
|
||||||
interface.getNode(args.dest, **getNode_kwargs).setOwner(args.set_ham, is_licensed=True)
|
interface.getNode(args.dest, **getNode_kwargs).setOwner(args.set_ham, is_licensed=True)
|
||||||
@@ -434,6 +482,26 @@ def onConnected(interface):
|
|||||||
waitForAckNak = True
|
waitForAckNak = True
|
||||||
interface.getNode(args.dest, False, **getNode_kwargs).removeNode(args.remove_node)
|
interface.getNode(args.dest, False, **getNode_kwargs).removeNode(args.remove_node)
|
||||||
|
|
||||||
|
if args.set_favorite_node:
|
||||||
|
closeNow = True
|
||||||
|
waitForAckNak = True
|
||||||
|
interface.getNode(args.dest, False, **getNode_kwargs).setFavorite(args.set_favorite_node)
|
||||||
|
|
||||||
|
if args.remove_favorite_node:
|
||||||
|
closeNow = True
|
||||||
|
waitForAckNak = True
|
||||||
|
interface.getNode(args.dest, False, **getNode_kwargs).removeFavorite(args.remove_favorite_node)
|
||||||
|
|
||||||
|
if args.set_ignored_node:
|
||||||
|
closeNow = True
|
||||||
|
waitForAckNak = True
|
||||||
|
interface.getNode(args.dest, False, **getNode_kwargs).setIgnored(args.set_ignored_node)
|
||||||
|
|
||||||
|
if args.remove_ignored_node:
|
||||||
|
closeNow = True
|
||||||
|
waitForAckNak = True
|
||||||
|
interface.getNode(args.dest, False, **getNode_kwargs).removeIgnored(args.remove_ignored_node)
|
||||||
|
|
||||||
if args.reset_nodedb:
|
if args.reset_nodedb:
|
||||||
closeNow = True
|
closeNow = True
|
||||||
waitForAckNak = True
|
waitForAckNak = True
|
||||||
@@ -445,6 +513,7 @@ def onConnected(interface):
|
|||||||
if checkChannel(interface, channelIndex):
|
if checkChannel(interface, channelIndex):
|
||||||
print(
|
print(
|
||||||
f"Sending text message {args.sendtext} to {args.dest} on channelIndex:{channelIndex}"
|
f"Sending text message {args.sendtext} to {args.dest} on channelIndex:{channelIndex}"
|
||||||
|
f" {'using PRIVATE_APP port' if args.private else ''}"
|
||||||
)
|
)
|
||||||
interface.sendText(
|
interface.sendText(
|
||||||
args.sendtext,
|
args.sendtext,
|
||||||
@@ -452,6 +521,7 @@ def onConnected(interface):
|
|||||||
wantAck=True,
|
wantAck=True,
|
||||||
channelIndex=channelIndex,
|
channelIndex=channelIndex,
|
||||||
onResponse=interface.getNode(args.dest, False, **getNode_kwargs).onAckNak,
|
onResponse=interface.getNode(args.dest, False, **getNode_kwargs).onAckNak,
|
||||||
|
portNum=portnums_pb2.PortNum.PRIVATE_APP if args.private else portnums_pb2.PortNum.TEXT_MESSAGE_APP
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
meshtastic.util.our_exit(
|
meshtastic.util.our_exit(
|
||||||
@@ -481,6 +551,8 @@ def onConnected(interface):
|
|||||||
"air_quality": "air_quality_metrics",
|
"air_quality": "air_quality_metrics",
|
||||||
"airquality": "air_quality_metrics",
|
"airquality": "air_quality_metrics",
|
||||||
"power": "power_metrics",
|
"power": "power_metrics",
|
||||||
|
"localstats": "local_stats",
|
||||||
|
"local_stats": "local_stats",
|
||||||
}
|
}
|
||||||
telemType = telemMap.get(args.request_telemetry, "device_metrics")
|
telemType = telemMap.get(args.request_telemetry, "device_metrics")
|
||||||
print(
|
print(
|
||||||
@@ -555,6 +627,7 @@ def onConnected(interface):
|
|||||||
|
|
||||||
# Handle the int/float/bool arguments
|
# Handle the int/float/bool arguments
|
||||||
pref = None
|
pref = None
|
||||||
|
fields = set()
|
||||||
for pref in args.set:
|
for pref in args.set:
|
||||||
found = False
|
found = False
|
||||||
field = splitCompoundName(pref[0].lower())[0]
|
field = splitCompoundName(pref[0].lower())[0]
|
||||||
@@ -567,11 +640,19 @@ def onConnected(interface):
|
|||||||
)
|
)
|
||||||
found = setPref(config, pref[0], pref[1])
|
found = setPref(config, pref[0], pref[1])
|
||||||
if found:
|
if found:
|
||||||
|
fields.add(field)
|
||||||
break
|
break
|
||||||
|
|
||||||
if found:
|
if found:
|
||||||
print("Writing modified preferences to device")
|
print("Writing modified preferences to device")
|
||||||
node.writeConfig(field)
|
if len(fields) > 1:
|
||||||
|
print("Using a configuration transaction")
|
||||||
|
node.beginSettingsTransaction()
|
||||||
|
for field in fields:
|
||||||
|
print(f"Writing {field} configuration to device")
|
||||||
|
node.writeConfig(field)
|
||||||
|
if len(fields) > 1:
|
||||||
|
node.commitSettingsTransaction()
|
||||||
else:
|
else:
|
||||||
if mt_config.camel_case:
|
if mt_config.camel_case:
|
||||||
print(
|
print(
|
||||||
@@ -593,11 +674,20 @@ def onConnected(interface):
|
|||||||
interface.getNode(args.dest, False, **getNode_kwargs).beginSettingsTransaction()
|
interface.getNode(args.dest, False, **getNode_kwargs).beginSettingsTransaction()
|
||||||
|
|
||||||
if "owner" in configuration:
|
if "owner" in configuration:
|
||||||
|
# Validate owner name before setting
|
||||||
|
owner_name = str(configuration["owner"]).strip()
|
||||||
|
if not owner_name:
|
||||||
|
meshtastic.util.our_exit("ERROR: Long Name cannot be empty or contain only whitespace characters")
|
||||||
print(f"Setting device owner to {configuration['owner']}")
|
print(f"Setting device owner to {configuration['owner']}")
|
||||||
waitForAckNak = True
|
waitForAckNak = True
|
||||||
interface.getNode(args.dest, False, **getNode_kwargs).setOwner(configuration["owner"])
|
interface.getNode(args.dest, False, **getNode_kwargs).setOwner(configuration["owner"])
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
if "owner_short" in configuration:
|
if "owner_short" in configuration:
|
||||||
|
# Validate owner short name before setting
|
||||||
|
owner_short_name = str(configuration["owner_short"]).strip()
|
||||||
|
if not owner_short_name:
|
||||||
|
meshtastic.util.our_exit("ERROR: Short Name cannot be empty or contain only whitespace characters")
|
||||||
print(
|
print(
|
||||||
f"Setting device owner short to {configuration['owner_short']}"
|
f"Setting device owner short to {configuration['owner_short']}"
|
||||||
)
|
)
|
||||||
@@ -605,8 +695,13 @@ def onConnected(interface):
|
|||||||
interface.getNode(args.dest, False, **getNode_kwargs).setOwner(
|
interface.getNode(args.dest, False, **getNode_kwargs).setOwner(
|
||||||
long_name=None, short_name=configuration["owner_short"]
|
long_name=None, short_name=configuration["owner_short"]
|
||||||
)
|
)
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
if "ownerShort" in configuration:
|
if "ownerShort" in configuration:
|
||||||
|
# Validate owner short name before setting
|
||||||
|
owner_short_name = str(configuration["ownerShort"]).strip()
|
||||||
|
if not owner_short_name:
|
||||||
|
meshtastic.util.our_exit("ERROR: Short Name cannot be empty or contain only whitespace characters")
|
||||||
print(
|
print(
|
||||||
f"Setting device owner short to {configuration['ownerShort']}"
|
f"Setting device owner short to {configuration['ownerShort']}"
|
||||||
)
|
)
|
||||||
@@ -614,14 +709,27 @@ def onConnected(interface):
|
|||||||
interface.getNode(args.dest, False, **getNode_kwargs).setOwner(
|
interface.getNode(args.dest, False, **getNode_kwargs).setOwner(
|
||||||
long_name=None, short_name=configuration["ownerShort"]
|
long_name=None, short_name=configuration["ownerShort"]
|
||||||
)
|
)
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
if "channel_url" in configuration:
|
if "channel_url" in configuration:
|
||||||
print("Setting channel url to", configuration["channel_url"])
|
print("Setting channel url to", configuration["channel_url"])
|
||||||
interface.getNode(args.dest, **getNode_kwargs).setURL(configuration["channel_url"])
|
interface.getNode(args.dest, **getNode_kwargs).setURL(configuration["channel_url"])
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
if "channelUrl" in configuration:
|
if "channelUrl" in configuration:
|
||||||
print("Setting channel url to", configuration["channelUrl"])
|
print("Setting channel url to", configuration["channelUrl"])
|
||||||
interface.getNode(args.dest, **getNode_kwargs).setURL(configuration["channelUrl"])
|
interface.getNode(args.dest, **getNode_kwargs).setURL(configuration["channelUrl"])
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
if "canned_messages" in configuration:
|
||||||
|
print("Setting canned message messages to", configuration["canned_messages"])
|
||||||
|
interface.getNode(args.dest, **getNode_kwargs).set_canned_message(configuration["canned_messages"])
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
if "ringtone" in configuration:
|
||||||
|
print("Setting ringtone to", configuration["ringtone"])
|
||||||
|
interface.getNode(args.dest, **getNode_kwargs).set_ringtone(configuration["ringtone"])
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
if "location" in configuration:
|
if "location" in configuration:
|
||||||
alt = 0
|
alt = 0
|
||||||
@@ -640,6 +748,7 @@ def onConnected(interface):
|
|||||||
print(f"Fixing longitude at {lon} degrees")
|
print(f"Fixing longitude at {lon} degrees")
|
||||||
print("Setting device position")
|
print("Setting device position")
|
||||||
interface.localNode.setFixedPosition(lat, lon, alt)
|
interface.localNode.setFixedPosition(lat, lon, alt)
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
if "config" in configuration:
|
if "config" in configuration:
|
||||||
localConfig = interface.getNode(args.dest, **getNode_kwargs).localConfig
|
localConfig = interface.getNode(args.dest, **getNode_kwargs).localConfig
|
||||||
@@ -650,6 +759,7 @@ def onConnected(interface):
|
|||||||
interface.getNode(args.dest, **getNode_kwargs).writeConfig(
|
interface.getNode(args.dest, **getNode_kwargs).writeConfig(
|
||||||
meshtastic.util.camel_to_snake(section)
|
meshtastic.util.camel_to_snake(section)
|
||||||
)
|
)
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
if "module_config" in configuration:
|
if "module_config" in configuration:
|
||||||
moduleConfig = interface.getNode(args.dest, **getNode_kwargs).moduleConfig
|
moduleConfig = interface.getNode(args.dest, **getNode_kwargs).moduleConfig
|
||||||
@@ -662,6 +772,7 @@ def onConnected(interface):
|
|||||||
interface.getNode(args.dest, **getNode_kwargs).writeConfig(
|
interface.getNode(args.dest, **getNode_kwargs).writeConfig(
|
||||||
meshtastic.util.camel_to_snake(section)
|
meshtastic.util.camel_to_snake(section)
|
||||||
)
|
)
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
interface.getNode(args.dest, False, **getNode_kwargs).commitSettingsTransaction()
|
interface.getNode(args.dest, False, **getNode_kwargs).commitSettingsTransaction()
|
||||||
print("Writing modified configuration to device")
|
print("Writing modified configuration to device")
|
||||||
@@ -670,16 +781,31 @@ def onConnected(interface):
|
|||||||
if args.dest != BROADCAST_ADDR:
|
if args.dest != BROADCAST_ADDR:
|
||||||
print("Exporting configuration of remote nodes is not supported.")
|
print("Exporting configuration of remote nodes is not supported.")
|
||||||
return
|
return
|
||||||
# export the configuration (the opposite of '--configure')
|
|
||||||
closeNow = True
|
|
||||||
export_config(interface)
|
|
||||||
|
|
||||||
if args.seturl:
|
|
||||||
closeNow = True
|
closeNow = True
|
||||||
interface.getNode(args.dest, **getNode_kwargs).setURL(args.seturl)
|
config_txt = export_config(interface)
|
||||||
|
|
||||||
|
if args.export_config == "-":
|
||||||
|
# Output to stdout (preserves legacy use of `> file.yaml`)
|
||||||
|
print(config_txt)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
with open(args.export_config, "w", encoding="utf-8") as f:
|
||||||
|
f.write(config_txt)
|
||||||
|
print(f"Exported configuration to {args.export_config}")
|
||||||
|
except Exception as e:
|
||||||
|
meshtastic.util.our_exit(f"ERROR: Failed to write config file: {e}")
|
||||||
|
|
||||||
|
if args.ch_set_url:
|
||||||
|
closeNow = True
|
||||||
|
interface.getNode(args.dest, **getNode_kwargs).setURL(args.ch_set_url, addOnly=False)
|
||||||
|
|
||||||
# handle changing channels
|
# handle changing channels
|
||||||
|
|
||||||
|
if args.ch_add_url:
|
||||||
|
closeNow = True
|
||||||
|
interface.getNode(args.dest, **getNode_kwargs).setURL(args.ch_add_url, addOnly=True)
|
||||||
|
|
||||||
if args.ch_add:
|
if args.ch_add:
|
||||||
channelIndex = mt_config.channel_index
|
channelIndex = mt_config.channel_index
|
||||||
if channelIndex is not None:
|
if channelIndex is not None:
|
||||||
@@ -839,12 +965,14 @@ def onConnected(interface):
|
|||||||
if args.get_canned_message:
|
if args.get_canned_message:
|
||||||
closeNow = True
|
closeNow = True
|
||||||
print("")
|
print("")
|
||||||
interface.getNode(args.dest, **getNode_kwargs).get_canned_message()
|
messages = interface.getNode(args.dest, **getNode_kwargs).get_canned_message()
|
||||||
|
print(f"canned_plugin_message:{messages}")
|
||||||
|
|
||||||
if args.get_ringtone:
|
if args.get_ringtone:
|
||||||
closeNow = True
|
closeNow = True
|
||||||
print("")
|
print("")
|
||||||
interface.getNode(args.dest, **getNode_kwargs).get_ringtone()
|
ringtone = interface.getNode(args.dest, **getNode_kwargs).get_ringtone()
|
||||||
|
print(f"ringtone:{ringtone}")
|
||||||
|
|
||||||
if args.info:
|
if args.info:
|
||||||
print("")
|
print("")
|
||||||
@@ -881,7 +1009,11 @@ def onConnected(interface):
|
|||||||
if args.dest != BROADCAST_ADDR:
|
if args.dest != BROADCAST_ADDR:
|
||||||
print("Showing node list of a remote node is not supported.")
|
print("Showing node list of a remote node is not supported.")
|
||||||
return
|
return
|
||||||
interface.showNodes()
|
interface.showNodes(True, args.show_fields)
|
||||||
|
|
||||||
|
if args.show_fields and not args.nodes:
|
||||||
|
print("--show-fields can only be used with --nodes")
|
||||||
|
return
|
||||||
|
|
||||||
if args.qr or args.qr_all:
|
if args.qr or args.qr_all:
|
||||||
closeNow = True
|
closeNow = True
|
||||||
@@ -891,8 +1023,11 @@ def onConnected(interface):
|
|||||||
else:
|
else:
|
||||||
urldesc = "Primary channel URL"
|
urldesc = "Primary channel URL"
|
||||||
print(f"{urldesc}: {url}")
|
print(f"{urldesc}: {url}")
|
||||||
qr = pyqrcode.create(url)
|
if pyqrcode is not None:
|
||||||
print(qr.terminal())
|
qr = pyqrcode.create(url)
|
||||||
|
print(qr.terminal())
|
||||||
|
else:
|
||||||
|
print("Install pyqrcode to view a QR code printed to terminal.")
|
||||||
|
|
||||||
log_set: Optional = None # type: ignore[annotation-unchecked]
|
log_set: Optional = None # type: ignore[annotation-unchecked]
|
||||||
# we need to keep a reference to the logset so it doesn't get GCed early
|
# we need to keep a reference to the logset so it doesn't get GCed early
|
||||||
@@ -960,7 +1095,7 @@ def onConnected(interface):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def printConfig(config):
|
def printConfig(config) -> None:
|
||||||
"""print configuration"""
|
"""print configuration"""
|
||||||
objDesc = config.DESCRIPTOR
|
objDesc = config.DESCRIPTOR
|
||||||
for config_section in objDesc.fields:
|
for config_section in objDesc.fields:
|
||||||
@@ -977,12 +1112,12 @@ def printConfig(config):
|
|||||||
print(f" {temp_name}")
|
print(f" {temp_name}")
|
||||||
|
|
||||||
|
|
||||||
def onNode(node):
|
def onNode(node) -> None:
|
||||||
"""Callback invoked when the node DB changes"""
|
"""Callback invoked when the node DB changes"""
|
||||||
print(f"Node changed: {node}")
|
print(f"Node changed: {node}")
|
||||||
|
|
||||||
|
|
||||||
def subscribe():
|
def subscribe() -> None:
|
||||||
"""Subscribe to the topics the user probably wants to see, prints output to stdout"""
|
"""Subscribe to the topics the user probably wants to see, prints output to stdout"""
|
||||||
pub.subscribe(onReceive, "meshtastic.receive")
|
pub.subscribe(onReceive, "meshtastic.receive")
|
||||||
# pub.subscribe(onConnection, "meshtastic.connection")
|
# pub.subscribe(onConnection, "meshtastic.connection")
|
||||||
@@ -992,15 +1127,38 @@ def subscribe():
|
|||||||
|
|
||||||
# pub.subscribe(onNode, "meshtastic.node")
|
# pub.subscribe(onNode, "meshtastic.node")
|
||||||
|
|
||||||
|
def set_missing_flags_false(config_dict: dict, true_defaults: set[tuple[str, str]]) -> None:
|
||||||
|
"""Ensure that missing default=True keys are present in the config_dict and set to False."""
|
||||||
|
for path in true_defaults:
|
||||||
|
d = config_dict
|
||||||
|
for key in path[:-1]:
|
||||||
|
if key not in d or not isinstance(d[key], dict):
|
||||||
|
d[key] = {}
|
||||||
|
d = d[key]
|
||||||
|
if path[-1] not in d:
|
||||||
|
d[path[-1]] = False
|
||||||
|
|
||||||
def export_config(interface):
|
def export_config(interface) -> str:
|
||||||
"""used in --export-config"""
|
"""used in --export-config"""
|
||||||
configObj = {}
|
configObj = {}
|
||||||
|
|
||||||
|
# A list of configuration keys that should be set to False if they are missing
|
||||||
|
true_defaults = {
|
||||||
|
("bluetooth", "enabled"),
|
||||||
|
("lora", "sx126xRxBoostedGain"),
|
||||||
|
("lora", "txEnabled"),
|
||||||
|
("lora", "usePreset"),
|
||||||
|
("position", "positionBroadcastSmartEnabled"),
|
||||||
|
("security", "serialEnabled"),
|
||||||
|
("mqtt", "encryptionEnabled"),
|
||||||
|
}
|
||||||
|
|
||||||
owner = interface.getLongName()
|
owner = interface.getLongName()
|
||||||
owner_short = interface.getShortName()
|
owner_short = interface.getShortName()
|
||||||
channel_url = interface.localNode.getURL()
|
channel_url = interface.localNode.getURL()
|
||||||
myinfo = interface.getMyNodeInfo()
|
myinfo = interface.getMyNodeInfo()
|
||||||
|
canned_messages = interface.getCannedMessage()
|
||||||
|
ringtone = interface.getRingtone()
|
||||||
pos = myinfo.get("position")
|
pos = myinfo.get("position")
|
||||||
lat = None
|
lat = None
|
||||||
lon = None
|
lon = None
|
||||||
@@ -1019,13 +1177,18 @@ def export_config(interface):
|
|||||||
configObj["channelUrl"] = channel_url
|
configObj["channelUrl"] = channel_url
|
||||||
else:
|
else:
|
||||||
configObj["channel_url"] = channel_url
|
configObj["channel_url"] = channel_url
|
||||||
|
if canned_messages:
|
||||||
|
configObj["canned_messages"] = canned_messages
|
||||||
|
if ringtone:
|
||||||
|
configObj["ringtone"] = ringtone
|
||||||
# lat and lon don't make much sense without the other (so fill with 0s), and alt isn't meaningful without both
|
# lat and lon don't make much sense without the other (so fill with 0s), and alt isn't meaningful without both
|
||||||
if lat or lon:
|
if lat or lon:
|
||||||
configObj["location"] = {"lat": lat or float(0), "lon": lon or float(0)}
|
configObj["location"] = {"lat": lat or float(0), "lon": lon or float(0)}
|
||||||
if alt:
|
if alt:
|
||||||
configObj["location"]["alt"] = alt
|
configObj["location"]["alt"] = alt
|
||||||
|
|
||||||
config = MessageToDict(interface.localNode.localConfig)
|
config = MessageToDict(interface.localNode.localConfig) #checkme - Used as a dictionary here and a string below
|
||||||
|
#was used as a string here and a Dictionary above
|
||||||
if config:
|
if config:
|
||||||
# Convert inner keys to correct snake/camelCase
|
# Convert inner keys to correct snake/camelCase
|
||||||
prefs = {}
|
prefs = {}
|
||||||
@@ -1044,10 +1207,12 @@ def export_config(interface):
|
|||||||
for i in range(len(prefs[pref]['adminKey'])):
|
for i in range(len(prefs[pref]['adminKey'])):
|
||||||
prefs[pref]['adminKey'][i] = 'base64:' + prefs[pref]['adminKey'][i]
|
prefs[pref]['adminKey'][i] = 'base64:' + prefs[pref]['adminKey'][i]
|
||||||
if mt_config.camel_case:
|
if mt_config.camel_case:
|
||||||
configObj["config"] = config
|
configObj["config"] = config #Identical command here and 2 lines below?
|
||||||
else:
|
else:
|
||||||
configObj["config"] = config
|
configObj["config"] = config
|
||||||
|
|
||||||
|
set_missing_flags_false(configObj["config"], true_defaults)
|
||||||
|
|
||||||
module_config = MessageToDict(interface.localNode.moduleConfig)
|
module_config = MessageToDict(interface.localNode.moduleConfig)
|
||||||
if module_config:
|
if module_config:
|
||||||
# Convert inner keys to correct snake/camelCase
|
# Convert inner keys to correct snake/camelCase
|
||||||
@@ -1060,10 +1225,10 @@ def export_config(interface):
|
|||||||
else:
|
else:
|
||||||
configObj["module_config"] = prefs
|
configObj["module_config"] = prefs
|
||||||
|
|
||||||
config = "# start of Meshtastic configure yaml\n"
|
config_txt = "# start of Meshtastic configure yaml\n" #checkme - "config" (now changed to config_out)
|
||||||
config += yaml.dump(configObj)
|
#was used as a string here and a Dictionary above
|
||||||
print(config)
|
config_txt += yaml.dump(configObj)
|
||||||
return config
|
return config_txt
|
||||||
|
|
||||||
|
|
||||||
def create_power_meter():
|
def create_power_meter():
|
||||||
@@ -1119,6 +1284,22 @@ def common():
|
|||||||
meshtastic.util.support_info()
|
meshtastic.util.support_info()
|
||||||
meshtastic.util.our_exit("", 0)
|
meshtastic.util.our_exit("", 0)
|
||||||
|
|
||||||
|
# Early validation for owner names before attempting device connection
|
||||||
|
if hasattr(args, 'set_owner') and args.set_owner is not None:
|
||||||
|
stripped_long_name = args.set_owner.strip()
|
||||||
|
if not stripped_long_name:
|
||||||
|
meshtastic.util.our_exit("ERROR: Long Name cannot be empty or contain only whitespace characters")
|
||||||
|
|
||||||
|
if hasattr(args, 'set_owner_short') and args.set_owner_short is not None:
|
||||||
|
stripped_short_name = args.set_owner_short.strip()
|
||||||
|
if not stripped_short_name:
|
||||||
|
meshtastic.util.our_exit("ERROR: Short Name cannot be empty or contain only whitespace characters")
|
||||||
|
|
||||||
|
if hasattr(args, 'set_ham') and args.set_ham is not None:
|
||||||
|
stripped_ham_name = args.set_ham.strip()
|
||||||
|
if not stripped_ham_name:
|
||||||
|
meshtastic.util.our_exit("ERROR: Ham radio callsign cannot be empty or contain only whitespace characters")
|
||||||
|
|
||||||
if have_powermon:
|
if have_powermon:
|
||||||
create_power_meter()
|
create_power_meter()
|
||||||
|
|
||||||
@@ -1142,11 +1323,14 @@ def common():
|
|||||||
parser.print_help(sys.stderr)
|
parser.print_help(sys.stderr)
|
||||||
meshtastic.util.our_exit("", 1)
|
meshtastic.util.our_exit("", 1)
|
||||||
elif args.test:
|
elif args.test:
|
||||||
result = meshtastic.test.testAll()
|
if not have_test:
|
||||||
if not result:
|
meshtastic.util.our_exit("Test module could not be important. Ensure you have the 'dotmap' module installed.")
|
||||||
meshtastic.util.our_exit("Warning: Test was not successful.")
|
|
||||||
else:
|
else:
|
||||||
meshtastic.util.our_exit("Test was a success.", 0)
|
result = meshtastic.test.testAll()
|
||||||
|
if not result:
|
||||||
|
meshtastic.util.our_exit("Warning: Test was not successful.")
|
||||||
|
else:
|
||||||
|
meshtastic.util.our_exit("Test was a success.", 0)
|
||||||
else:
|
else:
|
||||||
if args.seriallog == "stdout":
|
if args.seriallog == "stdout":
|
||||||
logfile = sys.stdout
|
logfile = sys.stdout
|
||||||
@@ -1198,6 +1382,19 @@ def common():
|
|||||||
noProto=args.noproto,
|
noProto=args.noproto,
|
||||||
noNodes=args.no_nodes,
|
noNodes=args.no_nodes,
|
||||||
)
|
)
|
||||||
|
except FileNotFoundError:
|
||||||
|
# Handle the case where the serial device is not found
|
||||||
|
message = (
|
||||||
|
f"File Not Found Error:\n"
|
||||||
|
)
|
||||||
|
message += f" The serial device at '{args.port}' was not found.\n"
|
||||||
|
message += " Please check the following:\n"
|
||||||
|
message += " 1. Is the device connected properly?\n"
|
||||||
|
message += " 2. Is the correct serial port specified?\n"
|
||||||
|
message += " 3. Are the necessary drivers installed?\n"
|
||||||
|
message += " 4. Are you using a **power-only USB cable**? A power-only cable cannot transmit data.\n"
|
||||||
|
message += " Ensure you are using a **data-capable USB cable**.\n"
|
||||||
|
meshtastic.util.our_exit(message, 1)
|
||||||
except PermissionError as ex:
|
except PermissionError as ex:
|
||||||
username = os.getlogin()
|
username = os.getlogin()
|
||||||
message = "Permission Error:\n"
|
message = "Permission Error:\n"
|
||||||
@@ -1208,6 +1405,12 @@ def common():
|
|||||||
message += " After running that command, log out and re-login for it to take effect.\n"
|
message += " After running that command, log out and re-login for it to take effect.\n"
|
||||||
message += f"Error was:{ex}"
|
message += f"Error was:{ex}"
|
||||||
meshtastic.util.our_exit(message)
|
meshtastic.util.our_exit(message)
|
||||||
|
except OSError as ex:
|
||||||
|
message = f"OS Error:\n"
|
||||||
|
message += " The serial device couldn't be opened, it might be in use by another process.\n"
|
||||||
|
message += " Please close any applications or webpages that may be using the device and try again.\n"
|
||||||
|
message += f"\nOriginal error: {ex}"
|
||||||
|
meshtastic.util.our_exit(message)
|
||||||
if client.devPath is None:
|
if client.devPath is None:
|
||||||
try:
|
try:
|
||||||
client = meshtastic.tcp_interface.TCPInterface(
|
client = meshtastic.tcp_interface.TCPInterface(
|
||||||
@@ -1295,7 +1498,8 @@ def addSelectionArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentParser
|
|||||||
|
|
||||||
group.add_argument(
|
group.add_argument(
|
||||||
"--dest",
|
"--dest",
|
||||||
help="The destination node id for any sent commands, if not set '^all' or '^local' is assumed as appropriate",
|
help="The destination node id for any sent commands. If not set '^all' or '^local' is assumed."
|
||||||
|
"Use the node ID with a '!' or '0x' prefix or the node number.",
|
||||||
default=None,
|
default=None,
|
||||||
metavar="!xxxxxxxx",
|
metavar="!xxxxxxxx",
|
||||||
)
|
)
|
||||||
@@ -1323,8 +1527,10 @@ def addImportExportArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentPar
|
|||||||
)
|
)
|
||||||
group.add_argument(
|
group.add_argument(
|
||||||
"--export-config",
|
"--export-config",
|
||||||
help="Export the configuration in yaml(.yml) format.",
|
nargs="?",
|
||||||
action="store_true",
|
const="-", # default to "-" if no value provided
|
||||||
|
metavar="FILE",
|
||||||
|
help="Export device config as YAML (to stdout if no file given)"
|
||||||
)
|
)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@@ -1340,7 +1546,7 @@ def addConfigArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentParser:
|
|||||||
"--get",
|
"--get",
|
||||||
help=(
|
help=(
|
||||||
"Get a preferences field. Use an invalid field such as '0' to get a list of all fields."
|
"Get a preferences field. Use an invalid field such as '0' to get a list of all fields."
|
||||||
" Can use either snake_case or camelCase format. (ex: 'ls_secs' or 'lsSecs')"
|
" Can use either snake_case or camelCase format. (ex: 'power.ls_secs' or 'power.lsSecs')"
|
||||||
),
|
),
|
||||||
nargs=1,
|
nargs=1,
|
||||||
action="append",
|
action="append",
|
||||||
@@ -1349,7 +1555,11 @@ def addConfigArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentParser:
|
|||||||
|
|
||||||
group.add_argument(
|
group.add_argument(
|
||||||
"--set",
|
"--set",
|
||||||
help="Set a preferences field. Can use either snake_case or camelCase format. (ex: 'ls_secs' or 'lsSecs')",
|
help=(
|
||||||
|
"Set a preferences field. Can use either snake_case or camelCase format."
|
||||||
|
" (ex: 'power.ls_secs' or 'power.lsSecs'). May be less reliable when"
|
||||||
|
" setting properties from more than one configuration section."
|
||||||
|
),
|
||||||
nargs=2,
|
nargs=2,
|
||||||
action="append",
|
action="append",
|
||||||
metavar=("FIELD", "VALUE"),
|
metavar=("FIELD", "VALUE"),
|
||||||
@@ -1442,7 +1652,25 @@ def addConfigArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentParser:
|
|||||||
"--set-ham", help="Set licensed Ham ID and turn off encryption", action="store"
|
"--set-ham", help="Set licensed Ham ID and turn off encryption", action="store"
|
||||||
)
|
)
|
||||||
|
|
||||||
group.add_argument("--seturl", help="Set a channel URL", action="store")
|
group.add_argument(
|
||||||
|
"--set-is-unmessageable", "--set-is-unmessagable",
|
||||||
|
help="Set if a node is messageable or not", action="store"
|
||||||
|
)
|
||||||
|
|
||||||
|
group.add_argument(
|
||||||
|
"--ch-set-url", "--seturl",
|
||||||
|
help="Set all channels and set LoRa config from a supplied URL",
|
||||||
|
metavar="URL",
|
||||||
|
action="store"
|
||||||
|
)
|
||||||
|
|
||||||
|
group.add_argument(
|
||||||
|
"--ch-add-url",
|
||||||
|
help="Add secondary channels and set LoRa config from a supplied URL",
|
||||||
|
metavar="URL",
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@@ -1580,6 +1808,13 @@ def addLocalActionArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentPars
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
group.add_argument(
|
||||||
|
"--show-fields",
|
||||||
|
help="Specify fields to show (comma-separated) when using --nodes",
|
||||||
|
type=lambda s: s.split(','),
|
||||||
|
default=None
|
||||||
|
)
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def addRemoteActionArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentParser:
|
def addRemoteActionArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentParser:
|
||||||
@@ -1591,15 +1826,21 @@ def addRemoteActionArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentPar
|
|||||||
|
|
||||||
group.add_argument(
|
group.add_argument(
|
||||||
"--sendtext",
|
"--sendtext",
|
||||||
help="Send a text message. Can specify a destination '--dest' and/or channel index '--ch-index'.",
|
help="Send a text message. Can specify a destination '--dest', use of PRIVATE_APP port '--private', and/or channel index '--ch-index'.",
|
||||||
metavar="TEXT",
|
metavar="TEXT",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
group.add_argument(
|
||||||
|
"--private",
|
||||||
|
help="Optional argument for sending text messages to the PRIVATE_APP port. Use in combination with --sendtext.",
|
||||||
|
action="store_true"
|
||||||
|
)
|
||||||
|
|
||||||
group.add_argument(
|
group.add_argument(
|
||||||
"--traceroute",
|
"--traceroute",
|
||||||
help="Traceroute from connected node to a destination. "
|
help="Traceroute from connected node to a destination. "
|
||||||
"You need pass the destination ID as argument, like "
|
"You need pass the destination ID as argument, like "
|
||||||
"this: '--traceroute !ba4bf9d0' "
|
"this: '--traceroute !ba4bf9d0' | '--traceroute 0xba4bf9d0'"
|
||||||
"Only nodes with a shared channel can be traced.",
|
"Only nodes with a shared channel can be traced.",
|
||||||
metavar="!xxxxxxxx",
|
metavar="!xxxxxxxx",
|
||||||
)
|
)
|
||||||
@@ -1680,7 +1921,32 @@ def addRemoteAdminArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentPars
|
|||||||
|
|
||||||
group.add_argument(
|
group.add_argument(
|
||||||
"--remove-node",
|
"--remove-node",
|
||||||
help="Tell the destination node to remove a specific node from its DB, by node number or ID",
|
help="Tell the destination node to remove a specific node from its NodeDB. "
|
||||||
|
"Use the node ID with a '!' or '0x' prefix or the node number.",
|
||||||
|
metavar="!xxxxxxxx"
|
||||||
|
)
|
||||||
|
group.add_argument(
|
||||||
|
"--set-favorite-node",
|
||||||
|
help="Tell the destination node to set the specified node to be favorited on the NodeDB. "
|
||||||
|
"Use the node ID with a '!' or '0x' prefix or the node number.",
|
||||||
|
metavar="!xxxxxxxx"
|
||||||
|
)
|
||||||
|
group.add_argument(
|
||||||
|
"--remove-favorite-node",
|
||||||
|
help="Tell the destination node to set the specified node to be un-favorited on the NodeDB. "
|
||||||
|
"Use the node ID with a '!' or '0x' prefix or the node number.",
|
||||||
|
metavar="!xxxxxxxx"
|
||||||
|
)
|
||||||
|
group.add_argument(
|
||||||
|
"--set-ignored-node",
|
||||||
|
help="Tell the destination node to set the specified node to be ignored on the NodeDB. "
|
||||||
|
"Use the node ID with a '!' or '0x' prefix or the node number.",
|
||||||
|
metavar="!xxxxxxxx"
|
||||||
|
)
|
||||||
|
group.add_argument(
|
||||||
|
"--remove-ignored-node",
|
||||||
|
help="Tell the destination node to set the specified node to be un-ignored on the NodeDB. "
|
||||||
|
"Use the node ID with a '!' or '0x' prefix or the node number.",
|
||||||
metavar="!xxxxxxxx"
|
metavar="!xxxxxxxx"
|
||||||
)
|
)
|
||||||
group.add_argument(
|
group.add_argument(
|
||||||
@@ -1902,6 +2168,8 @@ def initParser():
|
|||||||
|
|
||||||
parser.set_defaults(deprecated=None)
|
parser.set_defaults(deprecated=None)
|
||||||
|
|
||||||
|
if argcomplete is not None:
|
||||||
|
argcomplete.autocomplete(parser)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
mt_config.args = args
|
mt_config.args = args
|
||||||
mt_config.parser = parser
|
mt_config.parser = parser
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import atexit
|
|||||||
import logging
|
import logging
|
||||||
import struct
|
import struct
|
||||||
import time
|
import time
|
||||||
|
import io
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
@@ -34,9 +35,9 @@ class BLEInterface(MeshInterface):
|
|||||||
self,
|
self,
|
||||||
address: Optional[str],
|
address: Optional[str],
|
||||||
noProto: bool = False,
|
noProto: bool = False,
|
||||||
debugOut=None,
|
debugOut: Optional[io.TextIOWrapper]=None,
|
||||||
noNodes: bool = False,
|
noNodes: bool = False,
|
||||||
):
|
) -> None:
|
||||||
MeshInterface.__init__(
|
MeshInterface.__init__(
|
||||||
self, debugOut=debugOut, noProto=noProto, noNodes=noNodes
|
self, debugOut=debugOut, noProto=noProto, noNodes=noNodes
|
||||||
)
|
)
|
||||||
@@ -82,7 +83,18 @@ class BLEInterface(MeshInterface):
|
|||||||
# Note: the on disconnected callback will call our self.close which will make us nicely wait for threads to exit
|
# Note: the on disconnected callback will call our self.close which will make us nicely wait for threads to exit
|
||||||
self._exit_handler = atexit.register(self.client.disconnect)
|
self._exit_handler = atexit.register(self.client.disconnect)
|
||||||
|
|
||||||
def from_num_handler(self, _, b): # pylint: disable=C0116
|
def __repr__(self):
|
||||||
|
rep = f"BLEInterface(address={self.client.address if self.client else None!r}"
|
||||||
|
if self.debugOut is not None:
|
||||||
|
rep += f", debugOut={self.debugOut!r}"
|
||||||
|
if self.noProto:
|
||||||
|
rep += ", noProto=True"
|
||||||
|
if self.noNodes:
|
||||||
|
rep += ", noNodes=True"
|
||||||
|
rep += ")"
|
||||||
|
return rep
|
||||||
|
|
||||||
|
def from_num_handler(self, _, b: bytes) -> None: # pylint: disable=C0116
|
||||||
"""Handle callbacks for fromnum notify.
|
"""Handle callbacks for fromnum notify.
|
||||||
Note: this method does not need to be async because it is just setting a bool.
|
Note: this method does not need to be async because it is just setting a bool.
|
||||||
"""
|
"""
|
||||||
@@ -150,26 +162,33 @@ class BLEInterface(MeshInterface):
|
|||||||
)
|
)
|
||||||
return addressed_devices[0]
|
return addressed_devices[0]
|
||||||
|
|
||||||
def _sanitize_address(address): # pylint: disable=E0213
|
def _sanitize_address(self, address: Optional[str]) -> Optional[str]: # pylint: disable=E0213
|
||||||
"Standardize BLE address by removing extraneous characters and lowercasing."
|
"Standardize BLE address by removing extraneous characters and lowercasing."
|
||||||
return address.replace("-", "").replace("_", "").replace(":", "").lower()
|
if address is None:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return address.replace("-", "").replace("_", "").replace(":", "").lower()
|
||||||
|
|
||||||
def connect(self, address: Optional[str] = None) -> "BLEClient":
|
def connect(self, address: Optional[str] = None) -> "BLEClient":
|
||||||
"Connect to a device by address."
|
"Connect to a device by address."
|
||||||
|
|
||||||
# Bleak docs recommend always doing a scan before connecting (even if we know addr)
|
# Bleak docs recommend always doing a scan before connecting (even if we know addr)
|
||||||
device = self.find_device(address)
|
device = self.find_device(address)
|
||||||
client = BLEClient(device.address, disconnected_callback=lambda _: self.close)
|
client = BLEClient(device.address, disconnected_callback=lambda _: self.close())
|
||||||
client.connect()
|
client.connect()
|
||||||
client.discover()
|
client.discover()
|
||||||
return client
|
return client
|
||||||
|
|
||||||
def _receiveFromRadioImpl(self):
|
def _receiveFromRadioImpl(self) -> None:
|
||||||
while self._want_receive:
|
while self._want_receive:
|
||||||
if self.should_read:
|
if self.should_read:
|
||||||
self.should_read = False
|
self.should_read = False
|
||||||
retries = 0
|
retries: int = 0
|
||||||
while self._want_receive:
|
while self._want_receive:
|
||||||
|
if self.client is None:
|
||||||
|
logging.debug(f"BLE client is None, shutting down")
|
||||||
|
self._want_receive = False
|
||||||
|
continue
|
||||||
try:
|
try:
|
||||||
b = bytes(self.client.read_gatt_char(FROMRADIO_UUID))
|
b = bytes(self.client.read_gatt_char(FROMRADIO_UUID))
|
||||||
except BleakDBusError as e:
|
except BleakDBusError as e:
|
||||||
@@ -194,8 +213,8 @@ class BLEInterface(MeshInterface):
|
|||||||
else:
|
else:
|
||||||
time.sleep(0.01)
|
time.sleep(0.01)
|
||||||
|
|
||||||
def _sendToRadioImpl(self, toRadio):
|
def _sendToRadioImpl(self, toRadio) -> None:
|
||||||
b = toRadio.SerializeToString()
|
b: bytes = toRadio.SerializeToString()
|
||||||
if b and self.client: # we silently ignore writes while we are shutting down
|
if b and self.client: # we silently ignore writes while we are shutting down
|
||||||
logging.debug(f"TORADIO write: {b.hex()}")
|
logging.debug(f"TORADIO write: {b.hex()}")
|
||||||
try:
|
try:
|
||||||
@@ -211,7 +230,7 @@ class BLEInterface(MeshInterface):
|
|||||||
time.sleep(0.01)
|
time.sleep(0.01)
|
||||||
self.should_read = True
|
self.should_read = True
|
||||||
|
|
||||||
def close(self):
|
def close(self) -> None:
|
||||||
try:
|
try:
|
||||||
MeshInterface.close(self)
|
MeshInterface.close(self)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -236,7 +255,7 @@ class BLEInterface(MeshInterface):
|
|||||||
class BLEClient:
|
class BLEClient:
|
||||||
"""Client for managing connection to a BLE device"""
|
"""Client for managing connection to a BLE device"""
|
||||||
|
|
||||||
def __init__(self, address=None, **kwargs):
|
def __init__(self, address=None, **kwargs) -> None:
|
||||||
self._eventLoop = asyncio.new_event_loop()
|
self._eventLoop = asyncio.new_event_loop()
|
||||||
self._eventThread = Thread(
|
self._eventThread = Thread(
|
||||||
target=self._run_event_loop, name="BLEClient", daemon=True
|
target=self._run_event_loop, name="BLEClient", daemon=True
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
"""Mesh Interface class
|
"""Mesh Interface class
|
||||||
"""
|
"""
|
||||||
# pylint: disable=R0917
|
# pylint: disable=R0917,C0302
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import math
|
||||||
import random
|
import random
|
||||||
|
import secrets
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
@@ -15,7 +17,11 @@ from decimal import Decimal
|
|||||||
from typing import Any, Callable, Dict, List, Optional, Union
|
from typing import Any, Callable, Dict, List, Optional, Union
|
||||||
|
|
||||||
import google.protobuf.json_format
|
import google.protobuf.json_format
|
||||||
import print_color # type: ignore[import-untyped]
|
try:
|
||||||
|
import print_color # type: ignore[import-untyped]
|
||||||
|
except ImportError as e:
|
||||||
|
print_color = None
|
||||||
|
|
||||||
from pubsub import pub # type: ignore[import-untyped]
|
from pubsub import pub # type: ignore[import-untyped]
|
||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
|
|
||||||
@@ -153,7 +159,7 @@ class MeshInterface: # pylint: disable=R0902
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def _printLogLine(line, interface):
|
def _printLogLine(line, interface):
|
||||||
"""Print a line of log output."""
|
"""Print a line of log output."""
|
||||||
if interface.debugOut == sys.stdout:
|
if print_color is not None and interface.debugOut == sys.stdout:
|
||||||
# this isn't quite correct (could cause false positives), but currently our formatting differs between different log representations
|
# this isn't quite correct (could cause false positives), but currently our formatting differs between different log representations
|
||||||
if "DEBUG" in line:
|
if "DEBUG" in line:
|
||||||
print_color.print(line, color="cyan", end=None)
|
print_color.print(line, color="cyan", end=None)
|
||||||
@@ -216,9 +222,42 @@ class MeshInterface: # pylint: disable=R0902
|
|||||||
return infos
|
return infos
|
||||||
|
|
||||||
def showNodes(
|
def showNodes(
|
||||||
self, includeSelf: bool = True
|
self, includeSelf: bool = True, showFields: Optional[List[str]] = None
|
||||||
) -> str: # pylint: disable=W0613
|
) -> str: # pylint: disable=W0613
|
||||||
"""Show table summary of nodes in mesh"""
|
"""Show table summary of nodes in mesh
|
||||||
|
|
||||||
|
Args:
|
||||||
|
includeSelf (bool): Include ourself in the output?
|
||||||
|
showFields (List[str]): List of fields to show in output
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_human_readable(name):
|
||||||
|
name_map = {
|
||||||
|
"user.longName": "User",
|
||||||
|
"user.id": "ID",
|
||||||
|
"user.shortName": "AKA",
|
||||||
|
"user.hwModel": "Hardware",
|
||||||
|
"user.publicKey": "Pubkey",
|
||||||
|
"user.role": "Role",
|
||||||
|
"position.latitude": "Latitude",
|
||||||
|
"position.longitude": "Longitude",
|
||||||
|
"position.altitude": "Altitude",
|
||||||
|
"deviceMetrics.batteryLevel": "Battery",
|
||||||
|
"deviceMetrics.channelUtilization": "Channel util.",
|
||||||
|
"deviceMetrics.airUtilTx": "Tx air util.",
|
||||||
|
"snr": "SNR",
|
||||||
|
"hopsAway": "Hops",
|
||||||
|
"channel": "Channel",
|
||||||
|
"lastHeard": "LastHeard",
|
||||||
|
"since": "Since",
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if name in name_map:
|
||||||
|
return name_map.get(name) # Default to a formatted guess
|
||||||
|
else:
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
def formatFloat(value, precision=2, unit="") -> Optional[str]:
|
def formatFloat(value, precision=2, unit="") -> Optional[str]:
|
||||||
"""Format a float value with precision."""
|
"""Format a float value with precision."""
|
||||||
@@ -240,6 +279,29 @@ class MeshInterface: # pylint: disable=R0902
|
|||||||
return None # not handling a timestamp from the future
|
return None # not handling a timestamp from the future
|
||||||
return _timeago(delta_secs)
|
return _timeago(delta_secs)
|
||||||
|
|
||||||
|
def getNestedValue(node_dict: Dict[str, Any], key_path: str) -> Any:
|
||||||
|
if key_path.index(".") < 0:
|
||||||
|
logging.debug("getNestedValue was called without a nested path.")
|
||||||
|
return None
|
||||||
|
keys = key_path.split(".")
|
||||||
|
value: Optional[Union[str, dict]] = node_dict
|
||||||
|
for key in keys:
|
||||||
|
if isinstance(value, dict):
|
||||||
|
value = value.get(key)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
return value
|
||||||
|
|
||||||
|
if showFields is None or len(showFields) == 0:
|
||||||
|
# The default set of fields to show (e.g., the status quo)
|
||||||
|
showFields = ["N", "user.longName", "user.id", "user.shortName", "user.hwModel", "user.publicKey",
|
||||||
|
"user.role", "position.latitude", "position.longitude", "position.altitude",
|
||||||
|
"deviceMetrics.batteryLevel", "deviceMetrics.channelUtilization",
|
||||||
|
"deviceMetrics.airUtilTx", "snr", "hopsAway", "channel", "lastHeard", "since"]
|
||||||
|
else:
|
||||||
|
# Always at least include the row number.
|
||||||
|
showFields.insert(0, "N")
|
||||||
|
|
||||||
rows: List[Dict[str, Any]] = []
|
rows: List[Dict[str, Any]] = []
|
||||||
if self.nodesByNum:
|
if self.nodesByNum:
|
||||||
logging.debug(f"self.nodes:{self.nodes}")
|
logging.debug(f"self.nodes:{self.nodes}")
|
||||||
@@ -248,65 +310,60 @@ class MeshInterface: # pylint: disable=R0902
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
presumptive_id = f"!{node['num']:08x}"
|
presumptive_id = f"!{node['num']:08x}"
|
||||||
row = {
|
|
||||||
"N": 0,
|
|
||||||
"User": f"Meshtastic {presumptive_id[-4:]}",
|
|
||||||
"ID": presumptive_id,
|
|
||||||
}
|
|
||||||
|
|
||||||
user = node.get("user")
|
# This allows the user to specify fields that wouldn't otherwise be included.
|
||||||
if user:
|
fields = {}
|
||||||
row.update(
|
for field in showFields:
|
||||||
{
|
if "." in field:
|
||||||
"User": user.get("longName", "N/A"),
|
raw_value = getNestedValue(node, field)
|
||||||
"AKA": user.get("shortName", "N/A"),
|
else:
|
||||||
"ID": user["id"],
|
# The "since" column is synthesized, it's not retrieved from the device. Get the
|
||||||
"Hardware": user.get("hwModel", "UNSET"),
|
# lastHeard value here, and then we'll format it properly below.
|
||||||
"Pubkey": user.get("publicKey", "UNSET"),
|
if field == "since":
|
||||||
}
|
raw_value = node.get("lastHeard")
|
||||||
)
|
|
||||||
|
|
||||||
pos = node.get("position")
|
|
||||||
if pos:
|
|
||||||
row.update(
|
|
||||||
{
|
|
||||||
"Latitude": formatFloat(pos.get("latitude"), 4, "°"),
|
|
||||||
"Longitude": formatFloat(pos.get("longitude"), 4, "°"),
|
|
||||||
"Altitude": formatFloat(pos.get("altitude"), 0, " m"),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
metrics = node.get("deviceMetrics")
|
|
||||||
if metrics:
|
|
||||||
batteryLevel = metrics.get("batteryLevel")
|
|
||||||
if batteryLevel is not None:
|
|
||||||
if batteryLevel == 0:
|
|
||||||
batteryString = "Powered"
|
|
||||||
else:
|
else:
|
||||||
batteryString = str(batteryLevel) + "%"
|
raw_value = node.get(field)
|
||||||
row.update({"Battery": batteryString})
|
|
||||||
row.update(
|
|
||||||
{
|
|
||||||
"Channel util.": formatFloat(
|
|
||||||
metrics.get("channelUtilization"), 2, "%"
|
|
||||||
),
|
|
||||||
"Tx air util.": formatFloat(
|
|
||||||
metrics.get("airUtilTx"), 2, "%"
|
|
||||||
),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
row.update(
|
formatted_value: Optional[str] = ""
|
||||||
{
|
|
||||||
"SNR": formatFloat(node.get("snr"), 2, " dB"),
|
|
||||||
"Hops Away": node.get("hopsAway", "0/unknown"),
|
|
||||||
"Channel": node.get("channel", 0),
|
|
||||||
"LastHeard": getLH(node.get("lastHeard")),
|
|
||||||
"Since": getTimeAgo(node.get("lastHeard")),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
rows.append(row)
|
# Some of these need special formatting or processing.
|
||||||
|
if field == "channel":
|
||||||
|
if raw_value is None:
|
||||||
|
formatted_value = "0"
|
||||||
|
elif field == "deviceMetrics.channelUtilization":
|
||||||
|
formatted_value = formatFloat(raw_value, 2, "%")
|
||||||
|
elif field == "deviceMetrics.airUtilTx":
|
||||||
|
formatted_value = formatFloat(raw_value, 2, "%")
|
||||||
|
elif field == "deviceMetrics.batteryLevel":
|
||||||
|
if raw_value in (0, 101):
|
||||||
|
formatted_value = "Powered"
|
||||||
|
else:
|
||||||
|
formatted_value = formatFloat(raw_value, 0, "%")
|
||||||
|
elif field == "lastHeard":
|
||||||
|
formatted_value = getLH(raw_value)
|
||||||
|
elif field == "position.latitude":
|
||||||
|
formatted_value = formatFloat(raw_value, 4, "°")
|
||||||
|
elif field == "position.longitude":
|
||||||
|
formatted_value = formatFloat(raw_value, 4, "°")
|
||||||
|
elif field == "position.altitude":
|
||||||
|
formatted_value = formatFloat(raw_value, 0, "m")
|
||||||
|
elif field == "since":
|
||||||
|
formatted_value = getTimeAgo(raw_value) or "N/A"
|
||||||
|
elif field == "snr":
|
||||||
|
formatted_value = formatFloat(raw_value, 0, " dB")
|
||||||
|
elif field == "user.shortName":
|
||||||
|
formatted_value = raw_value if raw_value is not None else f'Meshtastic {presumptive_id[-4:]}'
|
||||||
|
elif field == "user.id":
|
||||||
|
formatted_value = raw_value if raw_value is not None else presumptive_id
|
||||||
|
else:
|
||||||
|
formatted_value = raw_value # No special formatting
|
||||||
|
|
||||||
|
fields[field] = formatted_value
|
||||||
|
|
||||||
|
# Filter out any field in the data set that was not specified.
|
||||||
|
filteredData = {get_human_readable(k): v for k, v in fields.items() if k in showFields}
|
||||||
|
filteredData.update({get_human_readable(k): v for k, v in fields.items()})
|
||||||
|
rows.append(filteredData)
|
||||||
|
|
||||||
rows.sort(key=lambda r: r.get("LastHeard") or "0000", reverse=True)
|
rows.sort(key=lambda r: r.get("LastHeard") or "0000", reverse=True)
|
||||||
for i, row in enumerate(rows):
|
for i, row in enumerate(rows):
|
||||||
@@ -338,7 +395,7 @@ class MeshInterface: # pylint: disable=R0902
|
|||||||
if new_index != last_index:
|
if new_index != last_index:
|
||||||
retries_left = requestChannelAttempts - 1
|
retries_left = requestChannelAttempts - 1
|
||||||
if retries_left <= 0:
|
if retries_left <= 0:
|
||||||
our_exit(f"Error: Timed out waiting for channels, giving up")
|
our_exit("Error: Timed out waiting for channels, giving up")
|
||||||
print("Timed out trying to retrieve channel info, retrying")
|
print("Timed out trying to retrieve channel info, retrying")
|
||||||
n.requestChannels(startingIndex=new_index)
|
n.requestChannels(startingIndex=new_index)
|
||||||
last_index = new_index
|
last_index = new_index
|
||||||
@@ -354,6 +411,8 @@ class MeshInterface: # pylint: disable=R0902
|
|||||||
wantResponse: bool = False,
|
wantResponse: bool = False,
|
||||||
onResponse: Optional[Callable[[dict], Any]] = None,
|
onResponse: Optional[Callable[[dict], Any]] = None,
|
||||||
channelIndex: int = 0,
|
channelIndex: int = 0,
|
||||||
|
portNum: portnums_pb2.PortNum.ValueType = portnums_pb2.PortNum.TEXT_MESSAGE_APP,
|
||||||
|
replyId: Optional[int]=None,
|
||||||
):
|
):
|
||||||
"""Send a utf8 string to some other node, if the node has a display it
|
"""Send a utf8 string to some other node, if the node has a display it
|
||||||
will also be shown on the device.
|
will also be shown on the device.
|
||||||
@@ -364,12 +423,13 @@ class MeshInterface: # pylint: disable=R0902
|
|||||||
Keyword Arguments:
|
Keyword Arguments:
|
||||||
destinationId {nodeId or nodeNum} -- where to send this
|
destinationId {nodeId or nodeNum} -- where to send this
|
||||||
message (default: {BROADCAST_ADDR})
|
message (default: {BROADCAST_ADDR})
|
||||||
portNum -- the application portnum (similar to IP port numbers)
|
|
||||||
of the destination, see portnums.proto for a list
|
|
||||||
wantAck -- True if you want the message sent in a reliable manner
|
wantAck -- True if you want the message sent in a reliable manner
|
||||||
(with retries and ack/nak provided for delivery)
|
(with retries and ack/nak provided for delivery)
|
||||||
wantResponse -- True if you want the service on the other side to
|
wantResponse -- True if you want the service on the other side to
|
||||||
send an application layer response
|
send an application layer response
|
||||||
|
portNum -- the application portnum (similar to IP port numbers)
|
||||||
|
of the destination, see portnums.proto for a list
|
||||||
|
replyId -- the ID of the message that this packet is a response to
|
||||||
|
|
||||||
Returns the sent packet. The id field will be populated in this packet
|
Returns the sent packet. The id field will be populated in this packet
|
||||||
and can be used to track future message acks/naks.
|
and can be used to track future message acks/naks.
|
||||||
@@ -378,13 +438,60 @@ class MeshInterface: # pylint: disable=R0902
|
|||||||
return self.sendData(
|
return self.sendData(
|
||||||
text.encode("utf-8"),
|
text.encode("utf-8"),
|
||||||
destinationId,
|
destinationId,
|
||||||
portNum=portnums_pb2.PortNum.TEXT_MESSAGE_APP,
|
portNum=portNum,
|
||||||
wantAck=wantAck,
|
wantAck=wantAck,
|
||||||
wantResponse=wantResponse,
|
wantResponse=wantResponse,
|
||||||
onResponse=onResponse,
|
onResponse=onResponse,
|
||||||
channelIndex=channelIndex,
|
channelIndex=channelIndex,
|
||||||
|
replyId=replyId
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def sendAlert(
|
||||||
|
self,
|
||||||
|
text: str,
|
||||||
|
destinationId: Union[int, str] = BROADCAST_ADDR,
|
||||||
|
onResponse: Optional[Callable[[dict], Any]] = None,
|
||||||
|
channelIndex: int = 0,
|
||||||
|
):
|
||||||
|
"""Send an alert text to some other node. This is similar to a text message,
|
||||||
|
but carries a higher priority and is capable of generating special notifications
|
||||||
|
on certain clients.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
text {string} -- The text of the alert to send
|
||||||
|
|
||||||
|
Keyword Arguments:
|
||||||
|
destinationId {nodeId or nodeNum} -- where to send this
|
||||||
|
message (default: {BROADCAST_ADDR})
|
||||||
|
|
||||||
|
Returns the sent packet. The id field will be populated in this packet
|
||||||
|
and can be used to track future message acks/naks.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return self.sendData(
|
||||||
|
text.encode("utf-8"),
|
||||||
|
destinationId,
|
||||||
|
portNum=portnums_pb2.PortNum.ALERT_APP,
|
||||||
|
wantAck=False,
|
||||||
|
wantResponse=False,
|
||||||
|
onResponse=onResponse,
|
||||||
|
channelIndex=channelIndex,
|
||||||
|
priority=mesh_pb2.MeshPacket.Priority.ALERT
|
||||||
|
)
|
||||||
|
|
||||||
|
def sendMqttClientProxyMessage(self, topic: str, data: bytes):
|
||||||
|
"""Send an MQTT Client Proxy message to the radio.
|
||||||
|
|
||||||
|
Topic and data should be the MQTT topic and the message
|
||||||
|
payload from an MQTT broker, respectively."""
|
||||||
|
prox = mesh_pb2.MqttClientProxyMessage()
|
||||||
|
prox.topic = topic
|
||||||
|
prox.data = data
|
||||||
|
toRadio = mesh_pb2.ToRadio()
|
||||||
|
toRadio.mqttClientProxyMessage.CopyFrom(prox)
|
||||||
|
self._sendToRadio(toRadio)
|
||||||
|
|
||||||
def sendData(
|
def sendData(
|
||||||
self,
|
self,
|
||||||
data,
|
data,
|
||||||
@@ -398,6 +505,8 @@ class MeshInterface: # pylint: disable=R0902
|
|||||||
hopLimit: Optional[int]=None,
|
hopLimit: Optional[int]=None,
|
||||||
pkiEncrypted: Optional[bool]=False,
|
pkiEncrypted: Optional[bool]=False,
|
||||||
publicKey: Optional[bytes]=None,
|
publicKey: Optional[bytes]=None,
|
||||||
|
priority: mesh_pb2.MeshPacket.Priority.ValueType=mesh_pb2.MeshPacket.Priority.RELIABLE,
|
||||||
|
replyId: Optional[int]=None,
|
||||||
): # pylint: disable=R0913
|
): # pylint: disable=R0913
|
||||||
"""Send a data packet to some other node
|
"""Send a data packet to some other node
|
||||||
|
|
||||||
@@ -422,6 +531,7 @@ class MeshInterface: # pylint: disable=R0902
|
|||||||
will implicitly be true.
|
will implicitly be true.
|
||||||
channelIndex -- channel number to use
|
channelIndex -- channel number to use
|
||||||
hopLimit -- hop limit to use
|
hopLimit -- hop limit to use
|
||||||
|
replyId -- the ID of the message that this packet is a response to
|
||||||
|
|
||||||
Returns the sent packet. The id field will be populated in this packet
|
Returns the sent packet. The id field will be populated in this packet
|
||||||
and can be used to track future message acks/naks.
|
and can be used to track future message acks/naks.
|
||||||
@@ -449,6 +559,10 @@ class MeshInterface: # pylint: disable=R0902
|
|||||||
meshPacket.decoded.portnum = portNum
|
meshPacket.decoded.portnum = portNum
|
||||||
meshPacket.decoded.want_response = wantResponse
|
meshPacket.decoded.want_response = wantResponse
|
||||||
meshPacket.id = self._generatePacketId()
|
meshPacket.id = self._generatePacketId()
|
||||||
|
if replyId is not None:
|
||||||
|
meshPacket.decoded.reply_id = replyId
|
||||||
|
if priority is not None:
|
||||||
|
meshPacket.priority = priority
|
||||||
|
|
||||||
if onResponse is not None:
|
if onResponse is not None:
|
||||||
logging.debug(f"Setting a response handler for requestId {meshPacket.id}")
|
logging.debug(f"Setting a response handler for requestId {meshPacket.id}")
|
||||||
@@ -617,6 +731,8 @@ class MeshInterface: # pylint: disable=R0902
|
|||||||
r.air_quality_metrics.CopyFrom(telemetry_pb2.AirQualityMetrics())
|
r.air_quality_metrics.CopyFrom(telemetry_pb2.AirQualityMetrics())
|
||||||
elif telemetryType == "power_metrics":
|
elif telemetryType == "power_metrics":
|
||||||
r.power_metrics.CopyFrom(telemetry_pb2.PowerMetrics())
|
r.power_metrics.CopyFrom(telemetry_pb2.PowerMetrics())
|
||||||
|
elif telemetryType == "local_stats":
|
||||||
|
r.local_stats.CopyFrom(telemetry_pb2.LocalStats())
|
||||||
else: # fall through to device metrics
|
else: # fall through to device metrics
|
||||||
if self.nodesByNum is not None:
|
if self.nodesByNum is not None:
|
||||||
node = self.nodesByNum.get(self.localNode.nodeNum)
|
node = self.nodesByNum.get(self.localNode.nodeNum)
|
||||||
@@ -694,6 +810,113 @@ class MeshInterface: # pylint: disable=R0902
|
|||||||
"No response from node. At least firmware 2.1.22 is required on the destination node."
|
"No response from node. At least firmware 2.1.22 is required on the destination node."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def onResponseWaypoint(self, p: dict):
|
||||||
|
"""on response for waypoint"""
|
||||||
|
if p["decoded"]["portnum"] == "WAYPOINT_APP":
|
||||||
|
self._acknowledgment.receivedWaypoint = True
|
||||||
|
w = mesh_pb2.Waypoint()
|
||||||
|
w.ParseFromString(p["decoded"]["payload"])
|
||||||
|
print(f"Waypoint received: {w}")
|
||||||
|
elif p["decoded"]["portnum"] == "ROUTING_APP":
|
||||||
|
if p["decoded"]["routing"]["errorReason"] == "NO_RESPONSE":
|
||||||
|
our_exit(
|
||||||
|
"No response from node. At least firmware 2.1.22 is required on the destination node."
|
||||||
|
)
|
||||||
|
|
||||||
|
def sendWaypoint(
|
||||||
|
self,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
expire: int,
|
||||||
|
waypoint_id: Optional[int] = None,
|
||||||
|
latitude: float = 0.0,
|
||||||
|
longitude: float = 0.0,
|
||||||
|
destinationId: Union[int, str] = BROADCAST_ADDR,
|
||||||
|
wantAck: bool = True,
|
||||||
|
wantResponse: bool = False,
|
||||||
|
channelIndex: int = 0,
|
||||||
|
): # pylint: disable=R0913
|
||||||
|
"""
|
||||||
|
Send a waypoint packet to some other node (normally a broadcast)
|
||||||
|
|
||||||
|
Returns the sent packet. The id field will be populated in this packet and
|
||||||
|
can be used to track future message acks/naks.
|
||||||
|
"""
|
||||||
|
w = mesh_pb2.Waypoint()
|
||||||
|
w.name = name
|
||||||
|
w.description = description
|
||||||
|
w.expire = expire
|
||||||
|
if waypoint_id is None:
|
||||||
|
# Generate a waypoint's id, NOT a packet ID.
|
||||||
|
# same algorithm as https://github.com/meshtastic/js/blob/715e35d2374276a43ffa93c628e3710875d43907/src/meshDevice.ts#L791
|
||||||
|
seed = secrets.randbits(32)
|
||||||
|
w.id = math.floor(seed * math.pow(2, -32) * 1e9)
|
||||||
|
logging.debug(f"w.id:{w.id}")
|
||||||
|
else:
|
||||||
|
w.id = waypoint_id
|
||||||
|
if latitude != 0.0:
|
||||||
|
w.latitude_i = int(latitude * 1e7)
|
||||||
|
logging.debug(f"w.latitude_i:{w.latitude_i}")
|
||||||
|
if longitude != 0.0:
|
||||||
|
w.longitude_i = int(longitude * 1e7)
|
||||||
|
logging.debug(f"w.longitude_i:{w.longitude_i}")
|
||||||
|
|
||||||
|
if wantResponse:
|
||||||
|
onResponse = self.onResponseWaypoint
|
||||||
|
else:
|
||||||
|
onResponse = None
|
||||||
|
|
||||||
|
d = self.sendData(
|
||||||
|
w,
|
||||||
|
destinationId,
|
||||||
|
portNum=portnums_pb2.PortNum.WAYPOINT_APP,
|
||||||
|
wantAck=wantAck,
|
||||||
|
wantResponse=wantResponse,
|
||||||
|
onResponse=onResponse,
|
||||||
|
channelIndex=channelIndex,
|
||||||
|
)
|
||||||
|
if wantResponse:
|
||||||
|
self.waitForWaypoint()
|
||||||
|
return d
|
||||||
|
|
||||||
|
def deleteWaypoint(
|
||||||
|
self,
|
||||||
|
waypoint_id: int,
|
||||||
|
destinationId: Union[int, str] = BROADCAST_ADDR,
|
||||||
|
wantAck: bool = True,
|
||||||
|
wantResponse: bool = False,
|
||||||
|
channelIndex: int = 0,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Send a waypoint deletion packet to some other node (normally a broadcast)
|
||||||
|
|
||||||
|
NB: The id must be the waypoint's id and not the id of the packet creation.
|
||||||
|
|
||||||
|
Returns the sent packet. The id field will be populated in this packet and
|
||||||
|
can be used to track future message acks/naks.
|
||||||
|
"""
|
||||||
|
p = mesh_pb2.Waypoint()
|
||||||
|
p.id = waypoint_id
|
||||||
|
p.expire = 0
|
||||||
|
|
||||||
|
if wantResponse:
|
||||||
|
onResponse = self.onResponseWaypoint
|
||||||
|
else:
|
||||||
|
onResponse = None
|
||||||
|
|
||||||
|
d = self.sendData(
|
||||||
|
p,
|
||||||
|
destinationId,
|
||||||
|
portNum=portnums_pb2.PortNum.WAYPOINT_APP,
|
||||||
|
wantAck=wantAck,
|
||||||
|
wantResponse=wantResponse,
|
||||||
|
onResponse=onResponse,
|
||||||
|
channelIndex=channelIndex,
|
||||||
|
)
|
||||||
|
if wantResponse:
|
||||||
|
self.waitForWaypoint()
|
||||||
|
return d
|
||||||
|
|
||||||
def _addResponseHandler(
|
def _addResponseHandler(
|
||||||
self,
|
self,
|
||||||
requestId: int,
|
requestId: int,
|
||||||
@@ -739,8 +962,10 @@ class MeshInterface: # pylint: disable=R0902
|
|||||||
else:
|
else:
|
||||||
our_exit("Warning: No myInfo found.")
|
our_exit("Warning: No myInfo found.")
|
||||||
# A simple hex style nodeid - we can parse this without needing the DB
|
# A simple hex style nodeid - we can parse this without needing the DB
|
||||||
elif destinationId.startswith("!"):
|
elif isinstance(destinationId, str) and len(destinationId) >= 8:
|
||||||
nodeNum = int(destinationId[1:], 16)
|
# assuming some form of node id string such as !1234578 or 0x12345678
|
||||||
|
# always grab the last 8 items of the hexadecimal id str and parse to integer
|
||||||
|
nodeNum = int(destinationId[-8:], 16)
|
||||||
else:
|
else:
|
||||||
if self.nodes:
|
if self.nodes:
|
||||||
node = self.nodes.get(destinationId)
|
node = self.nodes.get(destinationId)
|
||||||
@@ -774,7 +999,7 @@ class MeshInterface: # pylint: disable=R0902
|
|||||||
toRadio.packet.CopyFrom(meshPacket)
|
toRadio.packet.CopyFrom(meshPacket)
|
||||||
if self.noProto:
|
if self.noProto:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
f"Not sending packet because protocol use is disabled by noProto"
|
"Not sending packet because protocol use is disabled by noProto"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logging.debug(f"Sending packet: {stripnl(meshPacket)}")
|
logging.debug(f"Sending packet: {stripnl(meshPacket)}")
|
||||||
@@ -818,6 +1043,12 @@ class MeshInterface: # pylint: disable=R0902
|
|||||||
if not success:
|
if not success:
|
||||||
raise MeshInterface.MeshInterfaceError("Timed out waiting for position")
|
raise MeshInterface.MeshInterfaceError("Timed out waiting for position")
|
||||||
|
|
||||||
|
def waitForWaypoint(self):
|
||||||
|
"""Wait for waypoint"""
|
||||||
|
success = self._timeout.waitForWaypoint(self._acknowledgment)
|
||||||
|
if not success:
|
||||||
|
raise MeshInterface.MeshInterfaceError("Timed out waiting for waypoint")
|
||||||
|
|
||||||
def getMyNodeInfo(self) -> Optional[Dict]:
|
def getMyNodeInfo(self) -> Optional[Dict]:
|
||||||
"""Get info about my node."""
|
"""Get info about my node."""
|
||||||
if self.myInfo is None or self.nodesByNum is None:
|
if self.myInfo is None or self.nodesByNum is None:
|
||||||
@@ -853,6 +1084,20 @@ class MeshInterface: # pylint: disable=R0902
|
|||||||
return user.get("publicKey", None)
|
return user.get("publicKey", None)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def getCannedMessage(self):
|
||||||
|
"""Get canned message"""
|
||||||
|
node = self.localNode
|
||||||
|
if node is not None:
|
||||||
|
return node.get_canned_message()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def getRingtone(self):
|
||||||
|
"""Get ringtone"""
|
||||||
|
node = self.localNode
|
||||||
|
if node is not None:
|
||||||
|
return node.get_ringtone()
|
||||||
|
return None
|
||||||
|
|
||||||
def _waitConnected(self, timeout=30.0):
|
def _waitConnected(self, timeout=30.0):
|
||||||
"""Block until the initial node db download is complete, or timeout
|
"""Block until the initial node db download is complete, or timeout
|
||||||
and raise an exception"""
|
and raise an exception"""
|
||||||
@@ -957,7 +1202,7 @@ class MeshInterface: # pylint: disable=R0902
|
|||||||
"""Send a ToRadio protobuf to the device"""
|
"""Send a ToRadio protobuf to the device"""
|
||||||
if self.noProto:
|
if self.noProto:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
f"Not sending packet because protocol use is disabled by noProto"
|
"Not sending packet because protocol use is disabled by noProto"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# logging.debug(f"Sending toRadio: {stripnl(toRadio)}")
|
# logging.debug(f"Sending toRadio: {stripnl(toRadio)}")
|
||||||
@@ -1099,6 +1344,14 @@ class MeshInterface: # pylint: disable=R0902
|
|||||||
self._handleLogRecord(fromRadio.log_record)
|
self._handleLogRecord(fromRadio.log_record)
|
||||||
elif fromRadio.HasField("queueStatus"):
|
elif fromRadio.HasField("queueStatus"):
|
||||||
self._handleQueueStatusFromRadio(fromRadio.queueStatus)
|
self._handleQueueStatusFromRadio(fromRadio.queueStatus)
|
||||||
|
elif fromRadio.HasField("clientNotification"):
|
||||||
|
publishingThread.queueWork(
|
||||||
|
lambda: pub.sendMessage(
|
||||||
|
"meshtastic.clientNotification",
|
||||||
|
notification=fromRadio.clientNotification,
|
||||||
|
interface=self,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
elif fromRadio.HasField("mqttClientProxyMessage"):
|
elif fromRadio.HasField("mqttClientProxyMessage"):
|
||||||
publishingThread.queueWork(
|
publishingThread.queueWork(
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ with rather more easily once the code is simplified by this change.
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from typing import Any, Optional
|
||||||
|
|
||||||
def reset():
|
def reset():
|
||||||
"""
|
"""
|
||||||
Restore the namespace to pristine condition.
|
Restore the namespace to pristine condition.
|
||||||
@@ -33,5 +35,5 @@ args = None
|
|||||||
parser = None
|
parser = None
|
||||||
channel_index = None
|
channel_index = None
|
||||||
logfile = None
|
logfile = None
|
||||||
tunnelInstance = None
|
tunnelInstance: Optional[Any] = None
|
||||||
camel_case = False
|
camel_case = False
|
||||||
|
|||||||
@@ -42,6 +42,25 @@ class Node:
|
|||||||
|
|
||||||
self.gotResponse = None
|
self.gotResponse = None
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
r = f"Node({self.iface!r}, 0x{self.nodeNum:08x}"
|
||||||
|
if self.noProto:
|
||||||
|
r += ", noProto=True"
|
||||||
|
if self._timeout.expireTimeout != 300:
|
||||||
|
r += ", timeout={self._timeout.expireTimeout!r}"
|
||||||
|
r += ")"
|
||||||
|
return r
|
||||||
|
|
||||||
|
def module_available(self, excluded_bit: int) -> bool:
|
||||||
|
"""Check DeviceMetadata.excluded_modules to see if a module is available."""
|
||||||
|
meta = getattr(self.iface, "metadata", None)
|
||||||
|
if meta is None:
|
||||||
|
return True
|
||||||
|
try:
|
||||||
|
return (meta.excluded_modules & excluded_bit) == 0
|
||||||
|
except Exception:
|
||||||
|
return True
|
||||||
|
|
||||||
def showChannels(self):
|
def showChannels(self):
|
||||||
"""Show human readable description of our channels."""
|
"""Show human readable description of our channels."""
|
||||||
print("Channels:")
|
print("Channels:")
|
||||||
@@ -121,7 +140,7 @@ class Node:
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
if config_values is not None:
|
if config_values is not None:
|
||||||
raw_config = getattr(getattr(adminMessage['raw'], oneof), field)
|
raw_config = getattr(getattr(adminMessage['raw'], oneof), camel_to_snake(field))
|
||||||
config_values.CopyFrom(raw_config)
|
config_values.CopyFrom(raw_config)
|
||||||
print(f"{str(camel_to_snake(field))}:\n{str(config_values)}")
|
print(f"{str(camel_to_snake(field))}:\n{str(config_values)}")
|
||||||
|
|
||||||
@@ -289,7 +308,7 @@ class Node:
|
|||||||
return c.index
|
return c.index
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def setOwner(self, long_name: Optional[str]=None, short_name: Optional[str]=None, is_licensed: bool=False):
|
def setOwner(self, long_name: Optional[str]=None, short_name: Optional[str]=None, is_licensed: bool=False, is_unmessagable: Optional[bool]=None):
|
||||||
"""Set device owner name"""
|
"""Set device owner name"""
|
||||||
logging.debug(f"in setOwner nodeNum:{self.nodeNum}")
|
logging.debug(f"in setOwner nodeNum:{self.nodeNum}")
|
||||||
self.ensureSessionKey()
|
self.ensureSessionKey()
|
||||||
@@ -298,19 +317,28 @@ class Node:
|
|||||||
nChars = 4
|
nChars = 4
|
||||||
if long_name is not None:
|
if long_name is not None:
|
||||||
long_name = long_name.strip()
|
long_name = long_name.strip()
|
||||||
|
# Validate that long_name is not empty or whitespace-only
|
||||||
|
if not long_name:
|
||||||
|
our_exit("ERROR: Long Name cannot be empty or contain only whitespace characters")
|
||||||
p.set_owner.long_name = long_name
|
p.set_owner.long_name = long_name
|
||||||
p.set_owner.is_licensed = is_licensed
|
p.set_owner.is_licensed = is_licensed
|
||||||
if short_name is not None:
|
if short_name is not None:
|
||||||
short_name = short_name.strip()
|
short_name = short_name.strip()
|
||||||
|
# Validate that short_name is not empty or whitespace-only
|
||||||
|
if not short_name:
|
||||||
|
our_exit("ERROR: Short Name cannot be empty or contain only whitespace characters")
|
||||||
if len(short_name) > nChars:
|
if len(short_name) > nChars:
|
||||||
short_name = short_name[:nChars]
|
short_name = short_name[:nChars]
|
||||||
print(f"Maximum is 4 characters, truncated to {short_name}")
|
print(f"Maximum is 4 characters, truncated to {short_name}")
|
||||||
p.set_owner.short_name = short_name
|
p.set_owner.short_name = short_name
|
||||||
|
if is_unmessagable is not None:
|
||||||
|
p.set_owner.is_unmessagable = is_unmessagable
|
||||||
|
|
||||||
# Note: These debug lines are used in unit tests
|
# Note: These debug lines are used in unit tests
|
||||||
logging.debug(f"p.set_owner.long_name:{p.set_owner.long_name}:")
|
logging.debug(f"p.set_owner.long_name:{p.set_owner.long_name}:")
|
||||||
logging.debug(f"p.set_owner.short_name:{p.set_owner.short_name}:")
|
logging.debug(f"p.set_owner.short_name:{p.set_owner.short_name}:")
|
||||||
logging.debug(f"p.set_owner.is_licensed:{p.set_owner.is_licensed}")
|
logging.debug(f"p.set_owner.is_licensed:{p.set_owner.is_licensed}")
|
||||||
|
logging.debug(f"p.set_owner.is_unmessagable:{p.set_owner.is_unmessagable}:")
|
||||||
# If sending to a remote node, wait for ACK/NAK
|
# If sending to a remote node, wait for ACK/NAK
|
||||||
if self == self.iface.localNode:
|
if self == self.iface.localNode:
|
||||||
onResponse = None
|
onResponse = None
|
||||||
@@ -337,14 +365,19 @@ class Node:
|
|||||||
s = s.replace("=", "").replace("+", "-").replace("/", "_")
|
s = s.replace("=", "").replace("+", "-").replace("/", "_")
|
||||||
return f"https://meshtastic.org/e/#{s}"
|
return f"https://meshtastic.org/e/#{s}"
|
||||||
|
|
||||||
def setURL(self, url):
|
def setURL(self, url: str, addOnly: bool = False):
|
||||||
"""Set mesh network URL"""
|
"""Set mesh network URL"""
|
||||||
if self.localConfig is None:
|
if self.localConfig is None or self.channels is None:
|
||||||
our_exit("Warning: No Config has been read")
|
our_exit("Warning: config or channels not loaded")
|
||||||
|
|
||||||
# URLs are of the form https://meshtastic.org/d/#{base64_channel_set}
|
# URLs are of the form https://meshtastic.org/d/#{base64_channel_set}
|
||||||
# Split on '/#' to find the base64 encoded channel settings
|
# Split on '/#' to find the base64 encoded channel settings
|
||||||
splitURL = url.split("/#")
|
if addOnly:
|
||||||
|
splitURL = url.split("/?add=true#")
|
||||||
|
else:
|
||||||
|
splitURL = url.split("/#")
|
||||||
|
if len(splitURL) == 1:
|
||||||
|
our_exit(f"Warning: Invalid URL '{url}'")
|
||||||
b64 = splitURL[-1]
|
b64 = splitURL[-1]
|
||||||
|
|
||||||
# We normally strip padding to make for a shorter URL, but the python parser doesn't like
|
# We normally strip padding to make for a shorter URL, but the python parser doesn't like
|
||||||
@@ -361,20 +394,36 @@ class Node:
|
|||||||
if len(channelSet.settings) == 0:
|
if len(channelSet.settings) == 0:
|
||||||
our_exit("Warning: There were no settings.")
|
our_exit("Warning: There were no settings.")
|
||||||
|
|
||||||
i = 0
|
if addOnly:
|
||||||
for chs in channelSet.settings:
|
# Add new channels with names not already present
|
||||||
ch = channel_pb2.Channel()
|
# Don't change existing channels
|
||||||
ch.role = (
|
for chs in channelSet.settings:
|
||||||
channel_pb2.Channel.Role.PRIMARY
|
channelExists = self.getChannelByName(chs.name)
|
||||||
if i == 0
|
if channelExists or chs.name == "":
|
||||||
else channel_pb2.Channel.Role.SECONDARY
|
print(f"Ignoring existing or empty channel \"{chs.name}\" from add URL")
|
||||||
)
|
continue
|
||||||
ch.index = i
|
ch = self.getDisabledChannel()
|
||||||
ch.settings.CopyFrom(chs)
|
if not ch:
|
||||||
self.channels[ch.index] = ch
|
our_exit("Warning: No free channels were found")
|
||||||
logging.debug(f"Channel i:{i} ch:{ch}")
|
ch.settings.CopyFrom(chs)
|
||||||
self.writeChannel(ch.index)
|
ch.role = channel_pb2.Channel.Role.SECONDARY
|
||||||
i = i + 1
|
print(f"Adding new channel '{chs.name}' to device")
|
||||||
|
self.writeChannel(ch.index)
|
||||||
|
else:
|
||||||
|
i = 0
|
||||||
|
for chs in channelSet.settings:
|
||||||
|
ch = channel_pb2.Channel()
|
||||||
|
ch.role = (
|
||||||
|
channel_pb2.Channel.Role.PRIMARY
|
||||||
|
if i == 0
|
||||||
|
else channel_pb2.Channel.Role.SECONDARY
|
||||||
|
)
|
||||||
|
ch.index = i
|
||||||
|
ch.settings.CopyFrom(chs)
|
||||||
|
self.channels[ch.index] = ch
|
||||||
|
logging.debug(f"Channel i:{i} ch:{ch}")
|
||||||
|
self.writeChannel(ch.index)
|
||||||
|
i = i + 1
|
||||||
|
|
||||||
p = admin_pb2.AdminMessage()
|
p = admin_pb2.AdminMessage()
|
||||||
p.set_config.lora.CopyFrom(channelSet.lora_config)
|
p.set_config.lora.CopyFrom(channelSet.lora_config)
|
||||||
@@ -402,6 +451,10 @@ class Node:
|
|||||||
def get_ringtone(self):
|
def get_ringtone(self):
|
||||||
"""Get the ringtone. Concatenate all pieces together and return a single string."""
|
"""Get the ringtone. Concatenate all pieces together and return a single string."""
|
||||||
logging.debug(f"in get_ringtone()")
|
logging.debug(f"in get_ringtone()")
|
||||||
|
if not self.module_available(mesh_pb2.EXTNOTIF_CONFIG):
|
||||||
|
logging.warning("External Notification module not present (excluded by firmware)")
|
||||||
|
return None
|
||||||
|
|
||||||
if not self.ringtone:
|
if not self.ringtone:
|
||||||
p1 = admin_pb2.AdminMessage()
|
p1 = admin_pb2.AdminMessage()
|
||||||
p1.get_ringtone_request = True
|
p1.get_ringtone_request = True
|
||||||
@@ -418,12 +471,14 @@ class Node:
|
|||||||
if self.ringtonePart:
|
if self.ringtonePart:
|
||||||
self.ringtone += self.ringtonePart
|
self.ringtone += self.ringtonePart
|
||||||
|
|
||||||
print(f"ringtone:{self.ringtone}")
|
|
||||||
logging.debug(f"ringtone:{self.ringtone}")
|
logging.debug(f"ringtone:{self.ringtone}")
|
||||||
return self.ringtone
|
return self.ringtone
|
||||||
|
|
||||||
def set_ringtone(self, ringtone):
|
def set_ringtone(self, ringtone):
|
||||||
"""Set the ringtone. The ringtone length must be less than 230 character."""
|
"""Set the ringtone. The ringtone length must be less than 230 character."""
|
||||||
|
if not self.module_available(mesh_pb2.EXTNOTIF_CONFIG):
|
||||||
|
logging.warning("External Notification module not present (excluded by firmware)")
|
||||||
|
return None
|
||||||
|
|
||||||
if len(ringtone) > 230:
|
if len(ringtone) > 230:
|
||||||
our_exit("Warning: The ringtone must be less than 230 characters.")
|
our_exit("Warning: The ringtone must be less than 230 characters.")
|
||||||
@@ -474,6 +529,9 @@ class Node:
|
|||||||
def get_canned_message(self):
|
def get_canned_message(self):
|
||||||
"""Get the canned message string. Concatenate all pieces together and return a single string."""
|
"""Get the canned message string. Concatenate all pieces together and return a single string."""
|
||||||
logging.debug(f"in get_canned_message()")
|
logging.debug(f"in get_canned_message()")
|
||||||
|
if not self.module_available(mesh_pb2.CANNEDMSG_CONFIG):
|
||||||
|
logging.warning("Canned Message module not present (excluded by firmware)")
|
||||||
|
return None
|
||||||
if not self.cannedPluginMessage:
|
if not self.cannedPluginMessage:
|
||||||
p1 = admin_pb2.AdminMessage()
|
p1 = admin_pb2.AdminMessage()
|
||||||
p1.get_canned_message_module_messages_request = True
|
p1.get_canned_message_module_messages_request = True
|
||||||
@@ -494,12 +552,14 @@ class Node:
|
|||||||
if self.cannedPluginMessageMessages:
|
if self.cannedPluginMessageMessages:
|
||||||
self.cannedPluginMessage += self.cannedPluginMessageMessages
|
self.cannedPluginMessage += self.cannedPluginMessageMessages
|
||||||
|
|
||||||
print(f"canned_plugin_message:{self.cannedPluginMessage}")
|
|
||||||
logging.debug(f"canned_plugin_message:{self.cannedPluginMessage}")
|
logging.debug(f"canned_plugin_message:{self.cannedPluginMessage}")
|
||||||
return self.cannedPluginMessage
|
return self.cannedPluginMessage
|
||||||
|
|
||||||
def set_canned_message(self, message):
|
def set_canned_message(self, message):
|
||||||
"""Set the canned message. The canned messages length must be less than 200 character."""
|
"""Set the canned message. The canned messages length must be less than 200 character."""
|
||||||
|
if not self.module_available(mesh_pb2.CANNEDMSG_CONFIG):
|
||||||
|
logging.warning("Canned Message module not present (excluded by firmware)")
|
||||||
|
return None
|
||||||
|
|
||||||
if len(message) > 200:
|
if len(message) > 200:
|
||||||
our_exit("Warning: The canned message must be less than 200 characters.")
|
our_exit("Warning: The canned message must be less than 200 characters.")
|
||||||
@@ -668,6 +728,78 @@ class Node:
|
|||||||
onResponse = self.onAckNak
|
onResponse = self.onAckNak
|
||||||
return self._sendAdmin(p, onResponse=onResponse)
|
return self._sendAdmin(p, onResponse=onResponse)
|
||||||
|
|
||||||
|
def setFavorite(self, nodeId: Union[int, str]):
|
||||||
|
"""Tell the node to set the specified node ID to be favorited on the NodeDB on the device"""
|
||||||
|
self.ensureSessionKey()
|
||||||
|
if isinstance(nodeId, str):
|
||||||
|
if nodeId.startswith("!"):
|
||||||
|
nodeId = int(nodeId[1:], 16)
|
||||||
|
else:
|
||||||
|
nodeId = int(nodeId)
|
||||||
|
|
||||||
|
p = admin_pb2.AdminMessage()
|
||||||
|
p.set_favorite_node = nodeId
|
||||||
|
|
||||||
|
if self == self.iface.localNode:
|
||||||
|
onResponse = None
|
||||||
|
else:
|
||||||
|
onResponse = self.onAckNak
|
||||||
|
return self._sendAdmin(p, onResponse=onResponse)
|
||||||
|
|
||||||
|
def removeFavorite(self, nodeId: Union[int, str]):
|
||||||
|
"""Tell the node to set the specified node ID to be un-favorited on the NodeDB on the device"""
|
||||||
|
self.ensureSessionKey()
|
||||||
|
if isinstance(nodeId, str):
|
||||||
|
if nodeId.startswith("!"):
|
||||||
|
nodeId = int(nodeId[1:], 16)
|
||||||
|
else:
|
||||||
|
nodeId = int(nodeId)
|
||||||
|
|
||||||
|
p = admin_pb2.AdminMessage()
|
||||||
|
p.remove_favorite_node = nodeId
|
||||||
|
|
||||||
|
if self == self.iface.localNode:
|
||||||
|
onResponse = None
|
||||||
|
else:
|
||||||
|
onResponse = self.onAckNak
|
||||||
|
return self._sendAdmin(p, onResponse=onResponse)
|
||||||
|
|
||||||
|
def setIgnored(self, nodeId: Union[int, str]):
|
||||||
|
"""Tell the node to set the specified node ID to be ignored on the NodeDB on the device"""
|
||||||
|
self.ensureSessionKey()
|
||||||
|
if isinstance(nodeId, str):
|
||||||
|
if nodeId.startswith("!"):
|
||||||
|
nodeId = int(nodeId[1:], 16)
|
||||||
|
else:
|
||||||
|
nodeId = int(nodeId)
|
||||||
|
|
||||||
|
p = admin_pb2.AdminMessage()
|
||||||
|
p.set_ignored_node = nodeId
|
||||||
|
|
||||||
|
if self == self.iface.localNode:
|
||||||
|
onResponse = None
|
||||||
|
else:
|
||||||
|
onResponse = self.onAckNak
|
||||||
|
return self._sendAdmin(p, onResponse=onResponse)
|
||||||
|
|
||||||
|
def removeIgnored(self, nodeId: Union[int, str]):
|
||||||
|
"""Tell the node to set the specified node ID to be un-ignored on the NodeDB on the device"""
|
||||||
|
self.ensureSessionKey()
|
||||||
|
if isinstance(nodeId, str):
|
||||||
|
if nodeId.startswith("!"):
|
||||||
|
nodeId = int(nodeId[1:], 16)
|
||||||
|
else:
|
||||||
|
nodeId = int(nodeId)
|
||||||
|
|
||||||
|
p = admin_pb2.AdminMessage()
|
||||||
|
p.remove_ignored_node = nodeId
|
||||||
|
|
||||||
|
if self == self.iface.localNode:
|
||||||
|
onResponse = None
|
||||||
|
else:
|
||||||
|
onResponse = self.onAckNak
|
||||||
|
return self._sendAdmin(p, onResponse=onResponse)
|
||||||
|
|
||||||
def resetNodeDb(self):
|
def resetNodeDb(self):
|
||||||
"""Tell the node to reset its list of nodes."""
|
"""Tell the node to reset its list of nodes."""
|
||||||
self.ensureSessionKey()
|
self.ensureSessionKey()
|
||||||
@@ -890,7 +1022,7 @@ class Node:
|
|||||||
p,
|
p,
|
||||||
self.nodeNum,
|
self.nodeNum,
|
||||||
portNum=portnums_pb2.PortNum.ADMIN_APP,
|
portNum=portnums_pb2.PortNum.ADMIN_APP,
|
||||||
wantAck=False,
|
wantAck=True,
|
||||||
wantResponse=wantResponse,
|
wantResponse=wantResponse,
|
||||||
onResponse=onResponse,
|
onResponse=onResponse,
|
||||||
channelIndex=adminIndex,
|
channelIndex=adminIndex,
|
||||||
|
|||||||
33
meshtastic/protobuf/admin_pb2.py
generated
33
meshtastic/protobuf/admin_pb2.py
generated
File diff suppressed because one or more lines are too long
282
meshtastic/protobuf/admin_pb2.pyi
generated
282
meshtastic/protobuf/admin_pb2.pyi
generated
@@ -12,6 +12,7 @@ import google.protobuf.message
|
|||||||
import meshtastic.protobuf.channel_pb2
|
import meshtastic.protobuf.channel_pb2
|
||||||
import meshtastic.protobuf.config_pb2
|
import meshtastic.protobuf.config_pb2
|
||||||
import meshtastic.protobuf.connection_status_pb2
|
import meshtastic.protobuf.connection_status_pb2
|
||||||
|
import meshtastic.protobuf.device_ui_pb2
|
||||||
import meshtastic.protobuf.mesh_pb2
|
import meshtastic.protobuf.mesh_pb2
|
||||||
import meshtastic.protobuf.module_config_pb2
|
import meshtastic.protobuf.module_config_pb2
|
||||||
import sys
|
import sys
|
||||||
@@ -73,7 +74,13 @@ class AdminMessage(google.protobuf.message.Message):
|
|||||||
TODO: REPLACE
|
TODO: REPLACE
|
||||||
"""
|
"""
|
||||||
SESSIONKEY_CONFIG: AdminMessage._ConfigType.ValueType # 8
|
SESSIONKEY_CONFIG: AdminMessage._ConfigType.ValueType # 8
|
||||||
""""""
|
"""
|
||||||
|
Session key config
|
||||||
|
"""
|
||||||
|
DEVICEUI_CONFIG: AdminMessage._ConfigType.ValueType # 9
|
||||||
|
"""
|
||||||
|
device-ui config
|
||||||
|
"""
|
||||||
|
|
||||||
class ConfigType(_ConfigType, metaclass=_ConfigTypeEnumTypeWrapper):
|
class ConfigType(_ConfigType, metaclass=_ConfigTypeEnumTypeWrapper):
|
||||||
"""
|
"""
|
||||||
@@ -113,7 +120,13 @@ class AdminMessage(google.protobuf.message.Message):
|
|||||||
TODO: REPLACE
|
TODO: REPLACE
|
||||||
"""
|
"""
|
||||||
SESSIONKEY_CONFIG: AdminMessage.ConfigType.ValueType # 8
|
SESSIONKEY_CONFIG: AdminMessage.ConfigType.ValueType # 8
|
||||||
""""""
|
"""
|
||||||
|
Session key config
|
||||||
|
"""
|
||||||
|
DEVICEUI_CONFIG: AdminMessage.ConfigType.ValueType # 9
|
||||||
|
"""
|
||||||
|
device-ui config
|
||||||
|
"""
|
||||||
|
|
||||||
class _ModuleConfigType:
|
class _ModuleConfigType:
|
||||||
ValueType = typing.NewType("ValueType", builtins.int)
|
ValueType = typing.NewType("ValueType", builtins.int)
|
||||||
@@ -232,6 +245,69 @@ class AdminMessage(google.protobuf.message.Message):
|
|||||||
TODO: REPLACE
|
TODO: REPLACE
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
class _BackupLocation:
|
||||||
|
ValueType = typing.NewType("ValueType", builtins.int)
|
||||||
|
V: typing_extensions.TypeAlias = ValueType
|
||||||
|
|
||||||
|
class _BackupLocationEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[AdminMessage._BackupLocation.ValueType], builtins.type):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
|
||||||
|
FLASH: AdminMessage._BackupLocation.ValueType # 0
|
||||||
|
"""
|
||||||
|
Backup to the internal flash
|
||||||
|
"""
|
||||||
|
SD: AdminMessage._BackupLocation.ValueType # 1
|
||||||
|
"""
|
||||||
|
Backup to the SD card
|
||||||
|
"""
|
||||||
|
|
||||||
|
class BackupLocation(_BackupLocation, metaclass=_BackupLocationEnumTypeWrapper): ...
|
||||||
|
FLASH: AdminMessage.BackupLocation.ValueType # 0
|
||||||
|
"""
|
||||||
|
Backup to the internal flash
|
||||||
|
"""
|
||||||
|
SD: AdminMessage.BackupLocation.ValueType # 1
|
||||||
|
"""
|
||||||
|
Backup to the SD card
|
||||||
|
"""
|
||||||
|
|
||||||
|
@typing.final
|
||||||
|
class InputEvent(google.protobuf.message.Message):
|
||||||
|
"""
|
||||||
|
Input event message to be sent to the node.
|
||||||
|
"""
|
||||||
|
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||||
|
|
||||||
|
EVENT_CODE_FIELD_NUMBER: builtins.int
|
||||||
|
KB_CHAR_FIELD_NUMBER: builtins.int
|
||||||
|
TOUCH_X_FIELD_NUMBER: builtins.int
|
||||||
|
TOUCH_Y_FIELD_NUMBER: builtins.int
|
||||||
|
event_code: builtins.int
|
||||||
|
"""
|
||||||
|
The input event code
|
||||||
|
"""
|
||||||
|
kb_char: builtins.int
|
||||||
|
"""
|
||||||
|
Keyboard character code
|
||||||
|
"""
|
||||||
|
touch_x: builtins.int
|
||||||
|
"""
|
||||||
|
The touch X coordinate
|
||||||
|
"""
|
||||||
|
touch_y: builtins.int
|
||||||
|
"""
|
||||||
|
The touch Y coordinate
|
||||||
|
"""
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
event_code: builtins.int = ...,
|
||||||
|
kb_char: builtins.int = ...,
|
||||||
|
touch_x: builtins.int = ...,
|
||||||
|
touch_y: builtins.int = ...,
|
||||||
|
) -> None: ...
|
||||||
|
def ClearField(self, field_name: typing.Literal["event_code", b"event_code", "kb_char", b"kb_char", "touch_x", b"touch_x", "touch_y", b"touch_y"]) -> None: ...
|
||||||
|
|
||||||
SESSION_PASSKEY_FIELD_NUMBER: builtins.int
|
SESSION_PASSKEY_FIELD_NUMBER: builtins.int
|
||||||
GET_CHANNEL_REQUEST_FIELD_NUMBER: builtins.int
|
GET_CHANNEL_REQUEST_FIELD_NUMBER: builtins.int
|
||||||
GET_CHANNEL_RESPONSE_FIELD_NUMBER: builtins.int
|
GET_CHANNEL_RESPONSE_FIELD_NUMBER: builtins.int
|
||||||
@@ -255,6 +331,10 @@ class AdminMessage(google.protobuf.message.Message):
|
|||||||
ENTER_DFU_MODE_REQUEST_FIELD_NUMBER: builtins.int
|
ENTER_DFU_MODE_REQUEST_FIELD_NUMBER: builtins.int
|
||||||
DELETE_FILE_REQUEST_FIELD_NUMBER: builtins.int
|
DELETE_FILE_REQUEST_FIELD_NUMBER: builtins.int
|
||||||
SET_SCALE_FIELD_NUMBER: builtins.int
|
SET_SCALE_FIELD_NUMBER: builtins.int
|
||||||
|
BACKUP_PREFERENCES_FIELD_NUMBER: builtins.int
|
||||||
|
RESTORE_PREFERENCES_FIELD_NUMBER: builtins.int
|
||||||
|
REMOVE_BACKUP_PREFERENCES_FIELD_NUMBER: builtins.int
|
||||||
|
SEND_INPUT_EVENT_FIELD_NUMBER: builtins.int
|
||||||
SET_OWNER_FIELD_NUMBER: builtins.int
|
SET_OWNER_FIELD_NUMBER: builtins.int
|
||||||
SET_CHANNEL_FIELD_NUMBER: builtins.int
|
SET_CHANNEL_FIELD_NUMBER: builtins.int
|
||||||
SET_CONFIG_FIELD_NUMBER: builtins.int
|
SET_CONFIG_FIELD_NUMBER: builtins.int
|
||||||
@@ -267,8 +347,15 @@ class AdminMessage(google.protobuf.message.Message):
|
|||||||
SET_FIXED_POSITION_FIELD_NUMBER: builtins.int
|
SET_FIXED_POSITION_FIELD_NUMBER: builtins.int
|
||||||
REMOVE_FIXED_POSITION_FIELD_NUMBER: builtins.int
|
REMOVE_FIXED_POSITION_FIELD_NUMBER: builtins.int
|
||||||
SET_TIME_ONLY_FIELD_NUMBER: builtins.int
|
SET_TIME_ONLY_FIELD_NUMBER: builtins.int
|
||||||
|
GET_UI_CONFIG_REQUEST_FIELD_NUMBER: builtins.int
|
||||||
|
GET_UI_CONFIG_RESPONSE_FIELD_NUMBER: builtins.int
|
||||||
|
STORE_UI_CONFIG_FIELD_NUMBER: builtins.int
|
||||||
|
SET_IGNORED_NODE_FIELD_NUMBER: builtins.int
|
||||||
|
REMOVE_IGNORED_NODE_FIELD_NUMBER: builtins.int
|
||||||
BEGIN_EDIT_SETTINGS_FIELD_NUMBER: builtins.int
|
BEGIN_EDIT_SETTINGS_FIELD_NUMBER: builtins.int
|
||||||
COMMIT_EDIT_SETTINGS_FIELD_NUMBER: builtins.int
|
COMMIT_EDIT_SETTINGS_FIELD_NUMBER: builtins.int
|
||||||
|
ADD_CONTACT_FIELD_NUMBER: builtins.int
|
||||||
|
KEY_VERIFICATION_FIELD_NUMBER: builtins.int
|
||||||
FACTORY_RESET_DEVICE_FIELD_NUMBER: builtins.int
|
FACTORY_RESET_DEVICE_FIELD_NUMBER: builtins.int
|
||||||
REBOOT_OTA_SECONDS_FIELD_NUMBER: builtins.int
|
REBOOT_OTA_SECONDS_FIELD_NUMBER: builtins.int
|
||||||
EXIT_SIMULATOR_FIELD_NUMBER: builtins.int
|
EXIT_SIMULATOR_FIELD_NUMBER: builtins.int
|
||||||
@@ -340,6 +427,18 @@ class AdminMessage(google.protobuf.message.Message):
|
|||||||
"""
|
"""
|
||||||
Set zero and offset for scale chips
|
Set zero and offset for scale chips
|
||||||
"""
|
"""
|
||||||
|
backup_preferences: global___AdminMessage.BackupLocation.ValueType
|
||||||
|
"""
|
||||||
|
Backup the node's preferences
|
||||||
|
"""
|
||||||
|
restore_preferences: global___AdminMessage.BackupLocation.ValueType
|
||||||
|
"""
|
||||||
|
Restore the node's preferences
|
||||||
|
"""
|
||||||
|
remove_backup_preferences: global___AdminMessage.BackupLocation.ValueType
|
||||||
|
"""
|
||||||
|
Remove backups of the node's preferences
|
||||||
|
"""
|
||||||
set_canned_message_module_messages: builtins.str
|
set_canned_message_module_messages: builtins.str
|
||||||
"""
|
"""
|
||||||
Set the Canned Message Module messages text.
|
Set the Canned Message Module messages text.
|
||||||
@@ -369,6 +468,18 @@ class AdminMessage(google.protobuf.message.Message):
|
|||||||
Set time only on the node
|
Set time only on the node
|
||||||
Convenience method to set the time on the node (as Net quality) without any other position data
|
Convenience method to set the time on the node (as Net quality) without any other position data
|
||||||
"""
|
"""
|
||||||
|
get_ui_config_request: builtins.bool
|
||||||
|
"""
|
||||||
|
Tell the node to send the stored ui data.
|
||||||
|
"""
|
||||||
|
set_ignored_node: builtins.int
|
||||||
|
"""
|
||||||
|
Set specified node-num to be ignored on the NodeDB on the device
|
||||||
|
"""
|
||||||
|
remove_ignored_node: builtins.int
|
||||||
|
"""
|
||||||
|
Set specified node-num to be un-ignored on the NodeDB on the device
|
||||||
|
"""
|
||||||
begin_edit_settings: builtins.bool
|
begin_edit_settings: builtins.bool
|
||||||
"""
|
"""
|
||||||
Begins an edit transaction for config, module config, owner, and channel settings changes
|
Begins an edit transaction for config, module config, owner, and channel settings changes
|
||||||
@@ -456,6 +567,13 @@ class AdminMessage(google.protobuf.message.Message):
|
|||||||
Respond with the mesh's nodes with their available gpio pins for RemoteHardware module use
|
Respond with the mesh's nodes with their available gpio pins for RemoteHardware module use
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def send_input_event(self) -> global___AdminMessage.InputEvent:
|
||||||
|
"""
|
||||||
|
Send an input event to the node.
|
||||||
|
This is used to trigger physical input events like button presses, touch events, etc.
|
||||||
|
"""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def set_owner(self) -> meshtastic.protobuf.mesh_pb2.User:
|
def set_owner(self) -> meshtastic.protobuf.mesh_pb2.User:
|
||||||
"""
|
"""
|
||||||
@@ -490,6 +608,30 @@ class AdminMessage(google.protobuf.message.Message):
|
|||||||
Set fixed position data on the node and then set the position.fixed_position = true
|
Set fixed position data on the node and then set the position.fixed_position = true
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def get_ui_config_response(self) -> meshtastic.protobuf.device_ui_pb2.DeviceUIConfig:
|
||||||
|
"""
|
||||||
|
Reply stored device ui data.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def store_ui_config(self) -> meshtastic.protobuf.device_ui_pb2.DeviceUIConfig:
|
||||||
|
"""
|
||||||
|
Tell the node to store UI data persistently.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def add_contact(self) -> global___SharedContact:
|
||||||
|
"""
|
||||||
|
Add a contact (User) to the nodedb
|
||||||
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def key_verification(self) -> global___KeyVerificationAdmin:
|
||||||
|
"""
|
||||||
|
Initiate or respond to a key verification request
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
@@ -516,6 +658,10 @@ class AdminMessage(google.protobuf.message.Message):
|
|||||||
enter_dfu_mode_request: builtins.bool = ...,
|
enter_dfu_mode_request: builtins.bool = ...,
|
||||||
delete_file_request: builtins.str = ...,
|
delete_file_request: builtins.str = ...,
|
||||||
set_scale: builtins.int = ...,
|
set_scale: builtins.int = ...,
|
||||||
|
backup_preferences: global___AdminMessage.BackupLocation.ValueType = ...,
|
||||||
|
restore_preferences: global___AdminMessage.BackupLocation.ValueType = ...,
|
||||||
|
remove_backup_preferences: global___AdminMessage.BackupLocation.ValueType = ...,
|
||||||
|
send_input_event: global___AdminMessage.InputEvent | None = ...,
|
||||||
set_owner: meshtastic.protobuf.mesh_pb2.User | None = ...,
|
set_owner: meshtastic.protobuf.mesh_pb2.User | None = ...,
|
||||||
set_channel: meshtastic.protobuf.channel_pb2.Channel | None = ...,
|
set_channel: meshtastic.protobuf.channel_pb2.Channel | None = ...,
|
||||||
set_config: meshtastic.protobuf.config_pb2.Config | None = ...,
|
set_config: meshtastic.protobuf.config_pb2.Config | None = ...,
|
||||||
@@ -528,8 +674,15 @@ class AdminMessage(google.protobuf.message.Message):
|
|||||||
set_fixed_position: meshtastic.protobuf.mesh_pb2.Position | None = ...,
|
set_fixed_position: meshtastic.protobuf.mesh_pb2.Position | None = ...,
|
||||||
remove_fixed_position: builtins.bool = ...,
|
remove_fixed_position: builtins.bool = ...,
|
||||||
set_time_only: builtins.int = ...,
|
set_time_only: builtins.int = ...,
|
||||||
|
get_ui_config_request: builtins.bool = ...,
|
||||||
|
get_ui_config_response: meshtastic.protobuf.device_ui_pb2.DeviceUIConfig | None = ...,
|
||||||
|
store_ui_config: meshtastic.protobuf.device_ui_pb2.DeviceUIConfig | None = ...,
|
||||||
|
set_ignored_node: builtins.int = ...,
|
||||||
|
remove_ignored_node: builtins.int = ...,
|
||||||
begin_edit_settings: builtins.bool = ...,
|
begin_edit_settings: builtins.bool = ...,
|
||||||
commit_edit_settings: builtins.bool = ...,
|
commit_edit_settings: builtins.bool = ...,
|
||||||
|
add_contact: global___SharedContact | None = ...,
|
||||||
|
key_verification: global___KeyVerificationAdmin | None = ...,
|
||||||
factory_reset_device: builtins.int = ...,
|
factory_reset_device: builtins.int = ...,
|
||||||
reboot_ota_seconds: builtins.int = ...,
|
reboot_ota_seconds: builtins.int = ...,
|
||||||
exit_simulator: builtins.bool = ...,
|
exit_simulator: builtins.bool = ...,
|
||||||
@@ -538,9 +691,9 @@ class AdminMessage(google.protobuf.message.Message):
|
|||||||
factory_reset_config: builtins.int = ...,
|
factory_reset_config: builtins.int = ...,
|
||||||
nodedb_reset: builtins.int = ...,
|
nodedb_reset: builtins.int = ...,
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
def HasField(self, field_name: typing.Literal["begin_edit_settings", b"begin_edit_settings", "commit_edit_settings", b"commit_edit_settings", "delete_file_request", b"delete_file_request", "enter_dfu_mode_request", b"enter_dfu_mode_request", "exit_simulator", b"exit_simulator", "factory_reset_config", b"factory_reset_config", "factory_reset_device", b"factory_reset_device", "get_canned_message_module_messages_request", b"get_canned_message_module_messages_request", "get_canned_message_module_messages_response", b"get_canned_message_module_messages_response", "get_channel_request", b"get_channel_request", "get_channel_response", b"get_channel_response", "get_config_request", b"get_config_request", "get_config_response", b"get_config_response", "get_device_connection_status_request", b"get_device_connection_status_request", "get_device_connection_status_response", b"get_device_connection_status_response", "get_device_metadata_request", b"get_device_metadata_request", "get_device_metadata_response", b"get_device_metadata_response", "get_module_config_request", b"get_module_config_request", "get_module_config_response", b"get_module_config_response", "get_node_remote_hardware_pins_request", b"get_node_remote_hardware_pins_request", "get_node_remote_hardware_pins_response", b"get_node_remote_hardware_pins_response", "get_owner_request", b"get_owner_request", "get_owner_response", b"get_owner_response", "get_ringtone_request", b"get_ringtone_request", "get_ringtone_response", b"get_ringtone_response", "nodedb_reset", b"nodedb_reset", "payload_variant", b"payload_variant", "reboot_ota_seconds", b"reboot_ota_seconds", "reboot_seconds", b"reboot_seconds", "remove_by_nodenum", b"remove_by_nodenum", "remove_favorite_node", b"remove_favorite_node", "remove_fixed_position", b"remove_fixed_position", "set_canned_message_module_messages", b"set_canned_message_module_messages", "set_channel", b"set_channel", "set_config", b"set_config", "set_favorite_node", b"set_favorite_node", "set_fixed_position", b"set_fixed_position", "set_ham_mode", b"set_ham_mode", "set_module_config", b"set_module_config", "set_owner", b"set_owner", "set_ringtone_message", b"set_ringtone_message", "set_scale", b"set_scale", "set_time_only", b"set_time_only", "shutdown_seconds", b"shutdown_seconds"]) -> builtins.bool: ...
|
def HasField(self, field_name: typing.Literal["add_contact", b"add_contact", "backup_preferences", b"backup_preferences", "begin_edit_settings", b"begin_edit_settings", "commit_edit_settings", b"commit_edit_settings", "delete_file_request", b"delete_file_request", "enter_dfu_mode_request", b"enter_dfu_mode_request", "exit_simulator", b"exit_simulator", "factory_reset_config", b"factory_reset_config", "factory_reset_device", b"factory_reset_device", "get_canned_message_module_messages_request", b"get_canned_message_module_messages_request", "get_canned_message_module_messages_response", b"get_canned_message_module_messages_response", "get_channel_request", b"get_channel_request", "get_channel_response", b"get_channel_response", "get_config_request", b"get_config_request", "get_config_response", b"get_config_response", "get_device_connection_status_request", b"get_device_connection_status_request", "get_device_connection_status_response", b"get_device_connection_status_response", "get_device_metadata_request", b"get_device_metadata_request", "get_device_metadata_response", b"get_device_metadata_response", "get_module_config_request", b"get_module_config_request", "get_module_config_response", b"get_module_config_response", "get_node_remote_hardware_pins_request", b"get_node_remote_hardware_pins_request", "get_node_remote_hardware_pins_response", b"get_node_remote_hardware_pins_response", "get_owner_request", b"get_owner_request", "get_owner_response", b"get_owner_response", "get_ringtone_request", b"get_ringtone_request", "get_ringtone_response", b"get_ringtone_response", "get_ui_config_request", b"get_ui_config_request", "get_ui_config_response", b"get_ui_config_response", "key_verification", b"key_verification", "nodedb_reset", b"nodedb_reset", "payload_variant", b"payload_variant", "reboot_ota_seconds", b"reboot_ota_seconds", "reboot_seconds", b"reboot_seconds", "remove_backup_preferences", b"remove_backup_preferences", "remove_by_nodenum", b"remove_by_nodenum", "remove_favorite_node", b"remove_favorite_node", "remove_fixed_position", b"remove_fixed_position", "remove_ignored_node", b"remove_ignored_node", "restore_preferences", b"restore_preferences", "send_input_event", b"send_input_event", "set_canned_message_module_messages", b"set_canned_message_module_messages", "set_channel", b"set_channel", "set_config", b"set_config", "set_favorite_node", b"set_favorite_node", "set_fixed_position", b"set_fixed_position", "set_ham_mode", b"set_ham_mode", "set_ignored_node", b"set_ignored_node", "set_module_config", b"set_module_config", "set_owner", b"set_owner", "set_ringtone_message", b"set_ringtone_message", "set_scale", b"set_scale", "set_time_only", b"set_time_only", "shutdown_seconds", b"shutdown_seconds", "store_ui_config", b"store_ui_config"]) -> builtins.bool: ...
|
||||||
def ClearField(self, field_name: typing.Literal["begin_edit_settings", b"begin_edit_settings", "commit_edit_settings", b"commit_edit_settings", "delete_file_request", b"delete_file_request", "enter_dfu_mode_request", b"enter_dfu_mode_request", "exit_simulator", b"exit_simulator", "factory_reset_config", b"factory_reset_config", "factory_reset_device", b"factory_reset_device", "get_canned_message_module_messages_request", b"get_canned_message_module_messages_request", "get_canned_message_module_messages_response", b"get_canned_message_module_messages_response", "get_channel_request", b"get_channel_request", "get_channel_response", b"get_channel_response", "get_config_request", b"get_config_request", "get_config_response", b"get_config_response", "get_device_connection_status_request", b"get_device_connection_status_request", "get_device_connection_status_response", b"get_device_connection_status_response", "get_device_metadata_request", b"get_device_metadata_request", "get_device_metadata_response", b"get_device_metadata_response", "get_module_config_request", b"get_module_config_request", "get_module_config_response", b"get_module_config_response", "get_node_remote_hardware_pins_request", b"get_node_remote_hardware_pins_request", "get_node_remote_hardware_pins_response", b"get_node_remote_hardware_pins_response", "get_owner_request", b"get_owner_request", "get_owner_response", b"get_owner_response", "get_ringtone_request", b"get_ringtone_request", "get_ringtone_response", b"get_ringtone_response", "nodedb_reset", b"nodedb_reset", "payload_variant", b"payload_variant", "reboot_ota_seconds", b"reboot_ota_seconds", "reboot_seconds", b"reboot_seconds", "remove_by_nodenum", b"remove_by_nodenum", "remove_favorite_node", b"remove_favorite_node", "remove_fixed_position", b"remove_fixed_position", "session_passkey", b"session_passkey", "set_canned_message_module_messages", b"set_canned_message_module_messages", "set_channel", b"set_channel", "set_config", b"set_config", "set_favorite_node", b"set_favorite_node", "set_fixed_position", b"set_fixed_position", "set_ham_mode", b"set_ham_mode", "set_module_config", b"set_module_config", "set_owner", b"set_owner", "set_ringtone_message", b"set_ringtone_message", "set_scale", b"set_scale", "set_time_only", b"set_time_only", "shutdown_seconds", b"shutdown_seconds"]) -> None: ...
|
def ClearField(self, field_name: typing.Literal["add_contact", b"add_contact", "backup_preferences", b"backup_preferences", "begin_edit_settings", b"begin_edit_settings", "commit_edit_settings", b"commit_edit_settings", "delete_file_request", b"delete_file_request", "enter_dfu_mode_request", b"enter_dfu_mode_request", "exit_simulator", b"exit_simulator", "factory_reset_config", b"factory_reset_config", "factory_reset_device", b"factory_reset_device", "get_canned_message_module_messages_request", b"get_canned_message_module_messages_request", "get_canned_message_module_messages_response", b"get_canned_message_module_messages_response", "get_channel_request", b"get_channel_request", "get_channel_response", b"get_channel_response", "get_config_request", b"get_config_request", "get_config_response", b"get_config_response", "get_device_connection_status_request", b"get_device_connection_status_request", "get_device_connection_status_response", b"get_device_connection_status_response", "get_device_metadata_request", b"get_device_metadata_request", "get_device_metadata_response", b"get_device_metadata_response", "get_module_config_request", b"get_module_config_request", "get_module_config_response", b"get_module_config_response", "get_node_remote_hardware_pins_request", b"get_node_remote_hardware_pins_request", "get_node_remote_hardware_pins_response", b"get_node_remote_hardware_pins_response", "get_owner_request", b"get_owner_request", "get_owner_response", b"get_owner_response", "get_ringtone_request", b"get_ringtone_request", "get_ringtone_response", b"get_ringtone_response", "get_ui_config_request", b"get_ui_config_request", "get_ui_config_response", b"get_ui_config_response", "key_verification", b"key_verification", "nodedb_reset", b"nodedb_reset", "payload_variant", b"payload_variant", "reboot_ota_seconds", b"reboot_ota_seconds", "reboot_seconds", b"reboot_seconds", "remove_backup_preferences", b"remove_backup_preferences", "remove_by_nodenum", b"remove_by_nodenum", "remove_favorite_node", b"remove_favorite_node", "remove_fixed_position", b"remove_fixed_position", "remove_ignored_node", b"remove_ignored_node", "restore_preferences", b"restore_preferences", "send_input_event", b"send_input_event", "session_passkey", b"session_passkey", "set_canned_message_module_messages", b"set_canned_message_module_messages", "set_channel", b"set_channel", "set_config", b"set_config", "set_favorite_node", b"set_favorite_node", "set_fixed_position", b"set_fixed_position", "set_ham_mode", b"set_ham_mode", "set_ignored_node", b"set_ignored_node", "set_module_config", b"set_module_config", "set_owner", b"set_owner", "set_ringtone_message", b"set_ringtone_message", "set_scale", b"set_scale", "set_time_only", b"set_time_only", "shutdown_seconds", b"shutdown_seconds", "store_ui_config", b"store_ui_config"]) -> None: ...
|
||||||
def WhichOneof(self, oneof_group: typing.Literal["payload_variant", b"payload_variant"]) -> typing.Literal["get_channel_request", "get_channel_response", "get_owner_request", "get_owner_response", "get_config_request", "get_config_response", "get_module_config_request", "get_module_config_response", "get_canned_message_module_messages_request", "get_canned_message_module_messages_response", "get_device_metadata_request", "get_device_metadata_response", "get_ringtone_request", "get_ringtone_response", "get_device_connection_status_request", "get_device_connection_status_response", "set_ham_mode", "get_node_remote_hardware_pins_request", "get_node_remote_hardware_pins_response", "enter_dfu_mode_request", "delete_file_request", "set_scale", "set_owner", "set_channel", "set_config", "set_module_config", "set_canned_message_module_messages", "set_ringtone_message", "remove_by_nodenum", "set_favorite_node", "remove_favorite_node", "set_fixed_position", "remove_fixed_position", "set_time_only", "begin_edit_settings", "commit_edit_settings", "factory_reset_device", "reboot_ota_seconds", "exit_simulator", "reboot_seconds", "shutdown_seconds", "factory_reset_config", "nodedb_reset"] | None: ...
|
def WhichOneof(self, oneof_group: typing.Literal["payload_variant", b"payload_variant"]) -> typing.Literal["get_channel_request", "get_channel_response", "get_owner_request", "get_owner_response", "get_config_request", "get_config_response", "get_module_config_request", "get_module_config_response", "get_canned_message_module_messages_request", "get_canned_message_module_messages_response", "get_device_metadata_request", "get_device_metadata_response", "get_ringtone_request", "get_ringtone_response", "get_device_connection_status_request", "get_device_connection_status_response", "set_ham_mode", "get_node_remote_hardware_pins_request", "get_node_remote_hardware_pins_response", "enter_dfu_mode_request", "delete_file_request", "set_scale", "backup_preferences", "restore_preferences", "remove_backup_preferences", "send_input_event", "set_owner", "set_channel", "set_config", "set_module_config", "set_canned_message_module_messages", "set_ringtone_message", "remove_by_nodenum", "set_favorite_node", "remove_favorite_node", "set_fixed_position", "remove_fixed_position", "set_time_only", "get_ui_config_request", "get_ui_config_response", "store_ui_config", "set_ignored_node", "remove_ignored_node", "begin_edit_settings", "commit_edit_settings", "add_contact", "key_verification", "factory_reset_device", "reboot_ota_seconds", "exit_simulator", "reboot_seconds", "shutdown_seconds", "factory_reset_config", "nodedb_reset"] | None: ...
|
||||||
|
|
||||||
global___AdminMessage = AdminMessage
|
global___AdminMessage = AdminMessage
|
||||||
|
|
||||||
@@ -609,3 +762,122 @@ class NodeRemoteHardwarePinsResponse(google.protobuf.message.Message):
|
|||||||
def ClearField(self, field_name: typing.Literal["node_remote_hardware_pins", b"node_remote_hardware_pins"]) -> None: ...
|
def ClearField(self, field_name: typing.Literal["node_remote_hardware_pins", b"node_remote_hardware_pins"]) -> None: ...
|
||||||
|
|
||||||
global___NodeRemoteHardwarePinsResponse = NodeRemoteHardwarePinsResponse
|
global___NodeRemoteHardwarePinsResponse = NodeRemoteHardwarePinsResponse
|
||||||
|
|
||||||
|
@typing.final
|
||||||
|
class SharedContact(google.protobuf.message.Message):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||||
|
|
||||||
|
NODE_NUM_FIELD_NUMBER: builtins.int
|
||||||
|
USER_FIELD_NUMBER: builtins.int
|
||||||
|
SHOULD_IGNORE_FIELD_NUMBER: builtins.int
|
||||||
|
node_num: builtins.int
|
||||||
|
"""
|
||||||
|
The node number of the contact
|
||||||
|
"""
|
||||||
|
should_ignore: builtins.bool
|
||||||
|
"""
|
||||||
|
Add this contact to the blocked / ignored list
|
||||||
|
"""
|
||||||
|
@property
|
||||||
|
def user(self) -> meshtastic.protobuf.mesh_pb2.User:
|
||||||
|
"""
|
||||||
|
The User of the contact
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
node_num: builtins.int = ...,
|
||||||
|
user: meshtastic.protobuf.mesh_pb2.User | None = ...,
|
||||||
|
should_ignore: builtins.bool = ...,
|
||||||
|
) -> None: ...
|
||||||
|
def HasField(self, field_name: typing.Literal["user", b"user"]) -> builtins.bool: ...
|
||||||
|
def ClearField(self, field_name: typing.Literal["node_num", b"node_num", "should_ignore", b"should_ignore", "user", b"user"]) -> None: ...
|
||||||
|
|
||||||
|
global___SharedContact = SharedContact
|
||||||
|
|
||||||
|
@typing.final
|
||||||
|
class KeyVerificationAdmin(google.protobuf.message.Message):
|
||||||
|
"""
|
||||||
|
This message is used by a client to initiate or complete a key verification
|
||||||
|
"""
|
||||||
|
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||||
|
|
||||||
|
class _MessageType:
|
||||||
|
ValueType = typing.NewType("ValueType", builtins.int)
|
||||||
|
V: typing_extensions.TypeAlias = ValueType
|
||||||
|
|
||||||
|
class _MessageTypeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[KeyVerificationAdmin._MessageType.ValueType], builtins.type):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
|
||||||
|
INITIATE_VERIFICATION: KeyVerificationAdmin._MessageType.ValueType # 0
|
||||||
|
"""
|
||||||
|
This is the first stage, where a client initiates
|
||||||
|
"""
|
||||||
|
PROVIDE_SECURITY_NUMBER: KeyVerificationAdmin._MessageType.ValueType # 1
|
||||||
|
"""
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
DO_VERIFY: KeyVerificationAdmin._MessageType.ValueType # 2
|
||||||
|
"""
|
||||||
|
Once the user has compared the verification message, this message notifies the node.
|
||||||
|
"""
|
||||||
|
DO_NOT_VERIFY: KeyVerificationAdmin._MessageType.ValueType # 3
|
||||||
|
"""
|
||||||
|
This is the cancel path, can be taken at any point
|
||||||
|
"""
|
||||||
|
|
||||||
|
class MessageType(_MessageType, metaclass=_MessageTypeEnumTypeWrapper):
|
||||||
|
"""
|
||||||
|
Three stages of this request.
|
||||||
|
"""
|
||||||
|
|
||||||
|
INITIATE_VERIFICATION: KeyVerificationAdmin.MessageType.ValueType # 0
|
||||||
|
"""
|
||||||
|
This is the first stage, where a client initiates
|
||||||
|
"""
|
||||||
|
PROVIDE_SECURITY_NUMBER: KeyVerificationAdmin.MessageType.ValueType # 1
|
||||||
|
"""
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
DO_VERIFY: KeyVerificationAdmin.MessageType.ValueType # 2
|
||||||
|
"""
|
||||||
|
Once the user has compared the verification message, this message notifies the node.
|
||||||
|
"""
|
||||||
|
DO_NOT_VERIFY: KeyVerificationAdmin.MessageType.ValueType # 3
|
||||||
|
"""
|
||||||
|
This is the cancel path, can be taken at any point
|
||||||
|
"""
|
||||||
|
|
||||||
|
MESSAGE_TYPE_FIELD_NUMBER: builtins.int
|
||||||
|
REMOTE_NODENUM_FIELD_NUMBER: builtins.int
|
||||||
|
NONCE_FIELD_NUMBER: builtins.int
|
||||||
|
SECURITY_NUMBER_FIELD_NUMBER: builtins.int
|
||||||
|
message_type: global___KeyVerificationAdmin.MessageType.ValueType
|
||||||
|
remote_nodenum: builtins.int
|
||||||
|
"""
|
||||||
|
The nodenum we're requesting
|
||||||
|
"""
|
||||||
|
nonce: builtins.int
|
||||||
|
"""
|
||||||
|
The nonce is used to track the connection
|
||||||
|
"""
|
||||||
|
security_number: builtins.int
|
||||||
|
"""
|
||||||
|
The 4 digit code generated by the remote node, and communicated outside the mesh
|
||||||
|
"""
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
message_type: global___KeyVerificationAdmin.MessageType.ValueType = ...,
|
||||||
|
remote_nodenum: builtins.int = ...,
|
||||||
|
nonce: builtins.int = ...,
|
||||||
|
security_number: builtins.int | None = ...,
|
||||||
|
) -> None: ...
|
||||||
|
def HasField(self, field_name: typing.Literal["_security_number", b"_security_number", "security_number", b"security_number"]) -> builtins.bool: ...
|
||||||
|
def ClearField(self, field_name: typing.Literal["_security_number", b"_security_number", "message_type", b"message_type", "nonce", b"nonce", "remote_nodenum", b"remote_nodenum", "security_number", b"security_number"]) -> None: ...
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_security_number", b"_security_number"]) -> typing.Literal["security_number"] | None: ...
|
||||||
|
|
||||||
|
global___KeyVerificationAdmin = KeyVerificationAdmin
|
||||||
|
|||||||
2
meshtastic/protobuf/atak_pb2.pyi
generated
2
meshtastic/protobuf/atak_pb2.pyi
generated
@@ -256,7 +256,7 @@ class TAKPacket(google.protobuf.message.Message):
|
|||||||
detail: builtins.bytes
|
detail: builtins.bytes
|
||||||
"""
|
"""
|
||||||
Generic CoT detail XML
|
Generic CoT detail XML
|
||||||
May be compressed / truncated by the sender
|
May be compressed / truncated by the sender (EUD)
|
||||||
"""
|
"""
|
||||||
@property
|
@property
|
||||||
def contact(self) -> global___Contact:
|
def contact(self) -> global___Contact:
|
||||||
|
|||||||
107
meshtastic/protobuf/config_pb2.py
generated
107
meshtastic/protobuf/config_pb2.py
generated
File diff suppressed because one or more lines are too long
260
meshtastic/protobuf/config_pb2.pyi
generated
260
meshtastic/protobuf/config_pb2.pyi
generated
@@ -9,6 +9,7 @@ import google.protobuf.descriptor
|
|||||||
import google.protobuf.internal.containers
|
import google.protobuf.internal.containers
|
||||||
import google.protobuf.internal.enum_type_wrapper
|
import google.protobuf.internal.enum_type_wrapper
|
||||||
import google.protobuf.message
|
import google.protobuf.message
|
||||||
|
import meshtastic.protobuf.device_ui_pb2
|
||||||
import sys
|
import sys
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
@@ -107,6 +108,14 @@ class Config(google.protobuf.message.Message):
|
|||||||
and automatic TAK PLI (position location information) broadcasts.
|
and automatic TAK PLI (position location information) broadcasts.
|
||||||
Uses position module configuration to determine TAK PLI broadcast interval.
|
Uses position module configuration to determine TAK PLI broadcast interval.
|
||||||
"""
|
"""
|
||||||
|
ROUTER_LATE: Config.DeviceConfig._Role.ValueType # 11
|
||||||
|
"""
|
||||||
|
Description: Will always rebroadcast packets, but will do so after all other modes.
|
||||||
|
Technical Details: Used for router nodes that are intended to provide additional coverage
|
||||||
|
in areas not already covered by other routers, or to bridge around problematic terrain,
|
||||||
|
but should not be given priority over other routers in order to avoid unnecessaraily
|
||||||
|
consuming hops.
|
||||||
|
"""
|
||||||
|
|
||||||
class Role(_Role, metaclass=_RoleEnumTypeWrapper):
|
class Role(_Role, metaclass=_RoleEnumTypeWrapper):
|
||||||
"""
|
"""
|
||||||
@@ -183,6 +192,14 @@ class Config(google.protobuf.message.Message):
|
|||||||
and automatic TAK PLI (position location information) broadcasts.
|
and automatic TAK PLI (position location information) broadcasts.
|
||||||
Uses position module configuration to determine TAK PLI broadcast interval.
|
Uses position module configuration to determine TAK PLI broadcast interval.
|
||||||
"""
|
"""
|
||||||
|
ROUTER_LATE: Config.DeviceConfig.Role.ValueType # 11
|
||||||
|
"""
|
||||||
|
Description: Will always rebroadcast packets, but will do so after all other modes.
|
||||||
|
Technical Details: Used for router nodes that are intended to provide additional coverage
|
||||||
|
in areas not already covered by other routers, or to bridge around problematic terrain,
|
||||||
|
but should not be given priority over other routers in order to avoid unnecessaraily
|
||||||
|
consuming hops.
|
||||||
|
"""
|
||||||
|
|
||||||
class _RebroadcastMode:
|
class _RebroadcastMode:
|
||||||
ValueType = typing.NewType("ValueType", builtins.int)
|
ValueType = typing.NewType("ValueType", builtins.int)
|
||||||
@@ -210,6 +227,15 @@ class Config(google.protobuf.message.Message):
|
|||||||
Ignores observed messages from foreign meshes like LOCAL_ONLY,
|
Ignores observed messages from foreign meshes like LOCAL_ONLY,
|
||||||
but takes it step further by also ignoring messages from nodenums not in the node's known list (NodeDB)
|
but takes it step further by also ignoring messages from nodenums not in the node's known list (NodeDB)
|
||||||
"""
|
"""
|
||||||
|
NONE: Config.DeviceConfig._RebroadcastMode.ValueType # 4
|
||||||
|
"""
|
||||||
|
Only permitted for SENSOR, TRACKER and TAK_TRACKER roles, this will inhibit all rebroadcasts, not unlike CLIENT_MUTE role.
|
||||||
|
"""
|
||||||
|
CORE_PORTNUMS_ONLY: Config.DeviceConfig._RebroadcastMode.ValueType # 5
|
||||||
|
"""
|
||||||
|
Ignores packets from non-standard portnums such as: TAK, RangeTest, PaxCounter, etc.
|
||||||
|
Only rebroadcasts packets with standard portnums: NodeInfo, Text, Position, Telemetry, and Routing.
|
||||||
|
"""
|
||||||
|
|
||||||
class RebroadcastMode(_RebroadcastMode, metaclass=_RebroadcastModeEnumTypeWrapper):
|
class RebroadcastMode(_RebroadcastMode, metaclass=_RebroadcastModeEnumTypeWrapper):
|
||||||
"""
|
"""
|
||||||
@@ -236,6 +262,82 @@ class Config(google.protobuf.message.Message):
|
|||||||
Ignores observed messages from foreign meshes like LOCAL_ONLY,
|
Ignores observed messages from foreign meshes like LOCAL_ONLY,
|
||||||
but takes it step further by also ignoring messages from nodenums not in the node's known list (NodeDB)
|
but takes it step further by also ignoring messages from nodenums not in the node's known list (NodeDB)
|
||||||
"""
|
"""
|
||||||
|
NONE: Config.DeviceConfig.RebroadcastMode.ValueType # 4
|
||||||
|
"""
|
||||||
|
Only permitted for SENSOR, TRACKER and TAK_TRACKER roles, this will inhibit all rebroadcasts, not unlike CLIENT_MUTE role.
|
||||||
|
"""
|
||||||
|
CORE_PORTNUMS_ONLY: Config.DeviceConfig.RebroadcastMode.ValueType # 5
|
||||||
|
"""
|
||||||
|
Ignores packets from non-standard portnums such as: TAK, RangeTest, PaxCounter, etc.
|
||||||
|
Only rebroadcasts packets with standard portnums: NodeInfo, Text, Position, Telemetry, and Routing.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class _BuzzerMode:
|
||||||
|
ValueType = typing.NewType("ValueType", builtins.int)
|
||||||
|
V: typing_extensions.TypeAlias = ValueType
|
||||||
|
|
||||||
|
class _BuzzerModeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[Config.DeviceConfig._BuzzerMode.ValueType], builtins.type):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
|
||||||
|
ALL_ENABLED: Config.DeviceConfig._BuzzerMode.ValueType # 0
|
||||||
|
"""
|
||||||
|
Default behavior.
|
||||||
|
Buzzer is enabled for all audio feedback including button presses and alerts.
|
||||||
|
"""
|
||||||
|
DISABLED: Config.DeviceConfig._BuzzerMode.ValueType # 1
|
||||||
|
"""
|
||||||
|
Disabled.
|
||||||
|
All buzzer audio feedback is disabled.
|
||||||
|
"""
|
||||||
|
NOTIFICATIONS_ONLY: Config.DeviceConfig._BuzzerMode.ValueType # 2
|
||||||
|
"""
|
||||||
|
Notifications Only.
|
||||||
|
Buzzer is enabled only for notifications and alerts, but not for button presses.
|
||||||
|
External notification config determines the specifics of the notification behavior.
|
||||||
|
"""
|
||||||
|
SYSTEM_ONLY: Config.DeviceConfig._BuzzerMode.ValueType # 3
|
||||||
|
"""
|
||||||
|
Non-notification system buzzer tones only.
|
||||||
|
Buzzer is enabled only for non-notification tones such as button presses, startup, shutdown, but not for alerts.
|
||||||
|
"""
|
||||||
|
DIRECT_MSG_ONLY: Config.DeviceConfig._BuzzerMode.ValueType # 4
|
||||||
|
"""
|
||||||
|
Direct Message notifications only.
|
||||||
|
Buzzer is enabled only for direct messages and alerts, but not for button presses.
|
||||||
|
External notification config determines the specifics of the notification behavior.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class BuzzerMode(_BuzzerMode, metaclass=_BuzzerModeEnumTypeWrapper):
|
||||||
|
"""
|
||||||
|
Defines buzzer behavior for audio feedback
|
||||||
|
"""
|
||||||
|
|
||||||
|
ALL_ENABLED: Config.DeviceConfig.BuzzerMode.ValueType # 0
|
||||||
|
"""
|
||||||
|
Default behavior.
|
||||||
|
Buzzer is enabled for all audio feedback including button presses and alerts.
|
||||||
|
"""
|
||||||
|
DISABLED: Config.DeviceConfig.BuzzerMode.ValueType # 1
|
||||||
|
"""
|
||||||
|
Disabled.
|
||||||
|
All buzzer audio feedback is disabled.
|
||||||
|
"""
|
||||||
|
NOTIFICATIONS_ONLY: Config.DeviceConfig.BuzzerMode.ValueType # 2
|
||||||
|
"""
|
||||||
|
Notifications Only.
|
||||||
|
Buzzer is enabled only for notifications and alerts, but not for button presses.
|
||||||
|
External notification config determines the specifics of the notification behavior.
|
||||||
|
"""
|
||||||
|
SYSTEM_ONLY: Config.DeviceConfig.BuzzerMode.ValueType # 3
|
||||||
|
"""
|
||||||
|
Non-notification system buzzer tones only.
|
||||||
|
Buzzer is enabled only for non-notification tones such as button presses, startup, shutdown, but not for alerts.
|
||||||
|
"""
|
||||||
|
DIRECT_MSG_ONLY: Config.DeviceConfig.BuzzerMode.ValueType # 4
|
||||||
|
"""
|
||||||
|
Direct Message notifications only.
|
||||||
|
Buzzer is enabled only for direct messages and alerts, but not for button presses.
|
||||||
|
External notification config determines the specifics of the notification behavior.
|
||||||
|
"""
|
||||||
|
|
||||||
ROLE_FIELD_NUMBER: builtins.int
|
ROLE_FIELD_NUMBER: builtins.int
|
||||||
SERIAL_ENABLED_FIELD_NUMBER: builtins.int
|
SERIAL_ENABLED_FIELD_NUMBER: builtins.int
|
||||||
@@ -248,6 +350,7 @@ class Config(google.protobuf.message.Message):
|
|||||||
DISABLE_TRIPLE_CLICK_FIELD_NUMBER: builtins.int
|
DISABLE_TRIPLE_CLICK_FIELD_NUMBER: builtins.int
|
||||||
TZDEF_FIELD_NUMBER: builtins.int
|
TZDEF_FIELD_NUMBER: builtins.int
|
||||||
LED_HEARTBEAT_DISABLED_FIELD_NUMBER: builtins.int
|
LED_HEARTBEAT_DISABLED_FIELD_NUMBER: builtins.int
|
||||||
|
BUZZER_MODE_FIELD_NUMBER: builtins.int
|
||||||
role: global___Config.DeviceConfig.Role.ValueType
|
role: global___Config.DeviceConfig.Role.ValueType
|
||||||
"""
|
"""
|
||||||
Sets the role of node
|
Sets the role of node
|
||||||
@@ -298,6 +401,11 @@ class Config(google.protobuf.message.Message):
|
|||||||
"""
|
"""
|
||||||
If true, disable the default blinking LED (LED_PIN) behavior on the device
|
If true, disable the default blinking LED (LED_PIN) behavior on the device
|
||||||
"""
|
"""
|
||||||
|
buzzer_mode: global___Config.DeviceConfig.BuzzerMode.ValueType
|
||||||
|
"""
|
||||||
|
Controls buzzer behavior for audio feedback
|
||||||
|
Defaults to ENABLED
|
||||||
|
"""
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
@@ -312,8 +420,9 @@ class Config(google.protobuf.message.Message):
|
|||||||
disable_triple_click: builtins.bool = ...,
|
disable_triple_click: builtins.bool = ...,
|
||||||
tzdef: builtins.str = ...,
|
tzdef: builtins.str = ...,
|
||||||
led_heartbeat_disabled: builtins.bool = ...,
|
led_heartbeat_disabled: builtins.bool = ...,
|
||||||
|
buzzer_mode: global___Config.DeviceConfig.BuzzerMode.ValueType = ...,
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
def ClearField(self, field_name: typing.Literal["button_gpio", b"button_gpio", "buzzer_gpio", b"buzzer_gpio", "disable_triple_click", b"disable_triple_click", "double_tap_as_button_press", b"double_tap_as_button_press", "is_managed", b"is_managed", "led_heartbeat_disabled", b"led_heartbeat_disabled", "node_info_broadcast_secs", b"node_info_broadcast_secs", "rebroadcast_mode", b"rebroadcast_mode", "role", b"role", "serial_enabled", b"serial_enabled", "tzdef", b"tzdef"]) -> None: ...
|
def ClearField(self, field_name: typing.Literal["button_gpio", b"button_gpio", "buzzer_gpio", b"buzzer_gpio", "buzzer_mode", b"buzzer_mode", "disable_triple_click", b"disable_triple_click", "double_tap_as_button_press", b"double_tap_as_button_press", "is_managed", b"is_managed", "led_heartbeat_disabled", b"led_heartbeat_disabled", "node_info_broadcast_secs", b"node_info_broadcast_secs", "rebroadcast_mode", b"rebroadcast_mode", "role", b"role", "serial_enabled", b"serial_enabled", "tzdef", b"tzdef"]) -> None: ...
|
||||||
|
|
||||||
@typing.final
|
@typing.final
|
||||||
class PositionConfig(google.protobuf.message.Message):
|
class PositionConfig(google.protobuf.message.Message):
|
||||||
@@ -674,6 +783,35 @@ class Config(google.protobuf.message.Message):
|
|||||||
use static ip address
|
use static ip address
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
class _ProtocolFlags:
|
||||||
|
ValueType = typing.NewType("ValueType", builtins.int)
|
||||||
|
V: typing_extensions.TypeAlias = ValueType
|
||||||
|
|
||||||
|
class _ProtocolFlagsEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[Config.NetworkConfig._ProtocolFlags.ValueType], builtins.type):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
|
||||||
|
NO_BROADCAST: Config.NetworkConfig._ProtocolFlags.ValueType # 0
|
||||||
|
"""
|
||||||
|
Do not broadcast packets over any network protocol
|
||||||
|
"""
|
||||||
|
UDP_BROADCAST: Config.NetworkConfig._ProtocolFlags.ValueType # 1
|
||||||
|
"""
|
||||||
|
Enable broadcasting packets via UDP over the local network
|
||||||
|
"""
|
||||||
|
|
||||||
|
class ProtocolFlags(_ProtocolFlags, metaclass=_ProtocolFlagsEnumTypeWrapper):
|
||||||
|
"""
|
||||||
|
Available flags auxiliary network protocols
|
||||||
|
"""
|
||||||
|
|
||||||
|
NO_BROADCAST: Config.NetworkConfig.ProtocolFlags.ValueType # 0
|
||||||
|
"""
|
||||||
|
Do not broadcast packets over any network protocol
|
||||||
|
"""
|
||||||
|
UDP_BROADCAST: Config.NetworkConfig.ProtocolFlags.ValueType # 1
|
||||||
|
"""
|
||||||
|
Enable broadcasting packets via UDP over the local network
|
||||||
|
"""
|
||||||
|
|
||||||
@typing.final
|
@typing.final
|
||||||
class IpV4Config(google.protobuf.message.Message):
|
class IpV4Config(google.protobuf.message.Message):
|
||||||
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||||
@@ -716,6 +854,8 @@ class Config(google.protobuf.message.Message):
|
|||||||
ADDRESS_MODE_FIELD_NUMBER: builtins.int
|
ADDRESS_MODE_FIELD_NUMBER: builtins.int
|
||||||
IPV4_CONFIG_FIELD_NUMBER: builtins.int
|
IPV4_CONFIG_FIELD_NUMBER: builtins.int
|
||||||
RSYSLOG_SERVER_FIELD_NUMBER: builtins.int
|
RSYSLOG_SERVER_FIELD_NUMBER: builtins.int
|
||||||
|
ENABLED_PROTOCOLS_FIELD_NUMBER: builtins.int
|
||||||
|
IPV6_ENABLED_FIELD_NUMBER: builtins.int
|
||||||
wifi_enabled: builtins.bool
|
wifi_enabled: builtins.bool
|
||||||
"""
|
"""
|
||||||
Enable WiFi (disables Bluetooth)
|
Enable WiFi (disables Bluetooth)
|
||||||
@@ -731,7 +871,7 @@ class Config(google.protobuf.message.Message):
|
|||||||
"""
|
"""
|
||||||
ntp_server: builtins.str
|
ntp_server: builtins.str
|
||||||
"""
|
"""
|
||||||
NTP server to use if WiFi is conneced, defaults to `0.pool.ntp.org`
|
NTP server to use if WiFi is conneced, defaults to `meshtastic.pool.ntp.org`
|
||||||
"""
|
"""
|
||||||
eth_enabled: builtins.bool
|
eth_enabled: builtins.bool
|
||||||
"""
|
"""
|
||||||
@@ -745,6 +885,14 @@ class Config(google.protobuf.message.Message):
|
|||||||
"""
|
"""
|
||||||
rsyslog Server and Port
|
rsyslog Server and Port
|
||||||
"""
|
"""
|
||||||
|
enabled_protocols: builtins.int
|
||||||
|
"""
|
||||||
|
Flags for enabling/disabling network protocols
|
||||||
|
"""
|
||||||
|
ipv6_enabled: builtins.bool
|
||||||
|
"""
|
||||||
|
Enable/Disable ipv6 support
|
||||||
|
"""
|
||||||
@property
|
@property
|
||||||
def ipv4_config(self) -> global___Config.NetworkConfig.IpV4Config:
|
def ipv4_config(self) -> global___Config.NetworkConfig.IpV4Config:
|
||||||
"""
|
"""
|
||||||
@@ -762,9 +910,11 @@ class Config(google.protobuf.message.Message):
|
|||||||
address_mode: global___Config.NetworkConfig.AddressMode.ValueType = ...,
|
address_mode: global___Config.NetworkConfig.AddressMode.ValueType = ...,
|
||||||
ipv4_config: global___Config.NetworkConfig.IpV4Config | None = ...,
|
ipv4_config: global___Config.NetworkConfig.IpV4Config | None = ...,
|
||||||
rsyslog_server: builtins.str = ...,
|
rsyslog_server: builtins.str = ...,
|
||||||
|
enabled_protocols: builtins.int = ...,
|
||||||
|
ipv6_enabled: builtins.bool = ...,
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
def HasField(self, field_name: typing.Literal["ipv4_config", b"ipv4_config"]) -> builtins.bool: ...
|
def HasField(self, field_name: typing.Literal["ipv4_config", b"ipv4_config"]) -> builtins.bool: ...
|
||||||
def ClearField(self, field_name: typing.Literal["address_mode", b"address_mode", "eth_enabled", b"eth_enabled", "ipv4_config", b"ipv4_config", "ntp_server", b"ntp_server", "rsyslog_server", b"rsyslog_server", "wifi_enabled", b"wifi_enabled", "wifi_psk", b"wifi_psk", "wifi_ssid", b"wifi_ssid"]) -> None: ...
|
def ClearField(self, field_name: typing.Literal["address_mode", b"address_mode", "enabled_protocols", b"enabled_protocols", "eth_enabled", b"eth_enabled", "ipv4_config", b"ipv4_config", "ipv6_enabled", b"ipv6_enabled", "ntp_server", b"ntp_server", "rsyslog_server", b"rsyslog_server", "wifi_enabled", b"wifi_enabled", "wifi_psk", b"wifi_psk", "wifi_ssid", b"wifi_ssid"]) -> None: ...
|
||||||
|
|
||||||
@typing.final
|
@typing.final
|
||||||
class DisplayConfig(google.protobuf.message.Message):
|
class DisplayConfig(google.protobuf.message.Message):
|
||||||
@@ -886,18 +1036,22 @@ class Config(google.protobuf.message.Message):
|
|||||||
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
|
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
|
||||||
OLED_AUTO: Config.DisplayConfig._OledType.ValueType # 0
|
OLED_AUTO: Config.DisplayConfig._OledType.ValueType # 0
|
||||||
"""
|
"""
|
||||||
Default / Auto
|
Default / Autodetect
|
||||||
"""
|
"""
|
||||||
OLED_SSD1306: Config.DisplayConfig._OledType.ValueType # 1
|
OLED_SSD1306: Config.DisplayConfig._OledType.ValueType # 1
|
||||||
"""
|
"""
|
||||||
Default / Auto
|
Default / Autodetect
|
||||||
"""
|
"""
|
||||||
OLED_SH1106: Config.DisplayConfig._OledType.ValueType # 2
|
OLED_SH1106: Config.DisplayConfig._OledType.ValueType # 2
|
||||||
"""
|
"""
|
||||||
Default / Auto
|
Default / Autodetect
|
||||||
"""
|
"""
|
||||||
OLED_SH1107: Config.DisplayConfig._OledType.ValueType # 3
|
OLED_SH1107: Config.DisplayConfig._OledType.ValueType # 3
|
||||||
"""
|
"""
|
||||||
|
Can not be auto detected but set by proto. Used for 128x64 screens
|
||||||
|
"""
|
||||||
|
OLED_SH1107_128_128: Config.DisplayConfig._OledType.ValueType # 4
|
||||||
|
"""
|
||||||
Can not be auto detected but set by proto. Used for 128x128 screens
|
Can not be auto detected but set by proto. Used for 128x128 screens
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -908,18 +1062,22 @@ class Config(google.protobuf.message.Message):
|
|||||||
|
|
||||||
OLED_AUTO: Config.DisplayConfig.OledType.ValueType # 0
|
OLED_AUTO: Config.DisplayConfig.OledType.ValueType # 0
|
||||||
"""
|
"""
|
||||||
Default / Auto
|
Default / Autodetect
|
||||||
"""
|
"""
|
||||||
OLED_SSD1306: Config.DisplayConfig.OledType.ValueType # 1
|
OLED_SSD1306: Config.DisplayConfig.OledType.ValueType # 1
|
||||||
"""
|
"""
|
||||||
Default / Auto
|
Default / Autodetect
|
||||||
"""
|
"""
|
||||||
OLED_SH1106: Config.DisplayConfig.OledType.ValueType # 2
|
OLED_SH1106: Config.DisplayConfig.OledType.ValueType # 2
|
||||||
"""
|
"""
|
||||||
Default / Auto
|
Default / Autodetect
|
||||||
"""
|
"""
|
||||||
OLED_SH1107: Config.DisplayConfig.OledType.ValueType # 3
|
OLED_SH1107: Config.DisplayConfig.OledType.ValueType # 3
|
||||||
"""
|
"""
|
||||||
|
Can not be auto detected but set by proto. Used for 128x64 screens
|
||||||
|
"""
|
||||||
|
OLED_SH1107_128_128: Config.DisplayConfig.OledType.ValueType # 4
|
||||||
|
"""
|
||||||
Can not be auto detected but set by proto. Used for 128x128 screens
|
Can not be auto detected but set by proto. Used for 128x128 screens
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -1048,6 +1206,7 @@ class Config(google.protobuf.message.Message):
|
|||||||
HEADING_BOLD_FIELD_NUMBER: builtins.int
|
HEADING_BOLD_FIELD_NUMBER: builtins.int
|
||||||
WAKE_ON_TAP_OR_MOTION_FIELD_NUMBER: builtins.int
|
WAKE_ON_TAP_OR_MOTION_FIELD_NUMBER: builtins.int
|
||||||
COMPASS_ORIENTATION_FIELD_NUMBER: builtins.int
|
COMPASS_ORIENTATION_FIELD_NUMBER: builtins.int
|
||||||
|
USE_12H_CLOCK_FIELD_NUMBER: builtins.int
|
||||||
screen_on_secs: builtins.int
|
screen_on_secs: builtins.int
|
||||||
"""
|
"""
|
||||||
Number of seconds the screen stays on after pressing the user button or receiving a message
|
Number of seconds the screen stays on after pressing the user button or receiving a message
|
||||||
@@ -1055,6 +1214,7 @@ class Config(google.protobuf.message.Message):
|
|||||||
"""
|
"""
|
||||||
gps_format: global___Config.DisplayConfig.GpsCoordinateFormat.ValueType
|
gps_format: global___Config.DisplayConfig.GpsCoordinateFormat.ValueType
|
||||||
"""
|
"""
|
||||||
|
Deprecated in 2.7.4: Unused
|
||||||
How the GPS coordinates are formatted on the OLED screen.
|
How the GPS coordinates are formatted on the OLED screen.
|
||||||
"""
|
"""
|
||||||
auto_screen_carousel_secs: builtins.int
|
auto_screen_carousel_secs: builtins.int
|
||||||
@@ -1095,6 +1255,11 @@ class Config(google.protobuf.message.Message):
|
|||||||
"""
|
"""
|
||||||
Indicates how to rotate or invert the compass output to accurate display on the display.
|
Indicates how to rotate or invert the compass output to accurate display on the display.
|
||||||
"""
|
"""
|
||||||
|
use_12h_clock: builtins.bool
|
||||||
|
"""
|
||||||
|
If false (default), the device will display the time in 24-hour format on screen.
|
||||||
|
If true, the device will display the time in 12-hour format on screen.
|
||||||
|
"""
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
@@ -1109,8 +1274,9 @@ class Config(google.protobuf.message.Message):
|
|||||||
heading_bold: builtins.bool = ...,
|
heading_bold: builtins.bool = ...,
|
||||||
wake_on_tap_or_motion: builtins.bool = ...,
|
wake_on_tap_or_motion: builtins.bool = ...,
|
||||||
compass_orientation: global___Config.DisplayConfig.CompassOrientation.ValueType = ...,
|
compass_orientation: global___Config.DisplayConfig.CompassOrientation.ValueType = ...,
|
||||||
|
use_12h_clock: builtins.bool = ...,
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
def ClearField(self, field_name: typing.Literal["auto_screen_carousel_secs", b"auto_screen_carousel_secs", "compass_north_top", b"compass_north_top", "compass_orientation", b"compass_orientation", "displaymode", b"displaymode", "flip_screen", b"flip_screen", "gps_format", b"gps_format", "heading_bold", b"heading_bold", "oled", b"oled", "screen_on_secs", b"screen_on_secs", "units", b"units", "wake_on_tap_or_motion", b"wake_on_tap_or_motion"]) -> None: ...
|
def ClearField(self, field_name: typing.Literal["auto_screen_carousel_secs", b"auto_screen_carousel_secs", "compass_north_top", b"compass_north_top", "compass_orientation", b"compass_orientation", "displaymode", b"displaymode", "flip_screen", b"flip_screen", "gps_format", b"gps_format", "heading_bold", b"heading_bold", "oled", b"oled", "screen_on_secs", b"screen_on_secs", "units", b"units", "use_12h_clock", b"use_12h_clock", "wake_on_tap_or_motion", b"wake_on_tap_or_motion"]) -> None: ...
|
||||||
|
|
||||||
@typing.final
|
@typing.final
|
||||||
class LoRaConfig(google.protobuf.message.Message):
|
class LoRaConfig(google.protobuf.message.Message):
|
||||||
@@ -1202,6 +1368,38 @@ class Config(google.protobuf.message.Message):
|
|||||||
"""
|
"""
|
||||||
Singapore 923mhz
|
Singapore 923mhz
|
||||||
"""
|
"""
|
||||||
|
PH_433: Config.LoRaConfig._RegionCode.ValueType # 19
|
||||||
|
"""
|
||||||
|
Philippines 433mhz
|
||||||
|
"""
|
||||||
|
PH_868: Config.LoRaConfig._RegionCode.ValueType # 20
|
||||||
|
"""
|
||||||
|
Philippines 868mhz
|
||||||
|
"""
|
||||||
|
PH_915: Config.LoRaConfig._RegionCode.ValueType # 21
|
||||||
|
"""
|
||||||
|
Philippines 915mhz
|
||||||
|
"""
|
||||||
|
ANZ_433: Config.LoRaConfig._RegionCode.ValueType # 22
|
||||||
|
"""
|
||||||
|
Australia / New Zealand 433MHz
|
||||||
|
"""
|
||||||
|
KZ_433: Config.LoRaConfig._RegionCode.ValueType # 23
|
||||||
|
"""
|
||||||
|
Kazakhstan 433MHz
|
||||||
|
"""
|
||||||
|
KZ_863: Config.LoRaConfig._RegionCode.ValueType # 24
|
||||||
|
"""
|
||||||
|
Kazakhstan 863MHz
|
||||||
|
"""
|
||||||
|
NP_865: Config.LoRaConfig._RegionCode.ValueType # 25
|
||||||
|
"""
|
||||||
|
Nepal 865MHz
|
||||||
|
"""
|
||||||
|
BR_902: Config.LoRaConfig._RegionCode.ValueType # 26
|
||||||
|
"""
|
||||||
|
Brazil 902MHz
|
||||||
|
"""
|
||||||
|
|
||||||
class RegionCode(_RegionCode, metaclass=_RegionCodeEnumTypeWrapper): ...
|
class RegionCode(_RegionCode, metaclass=_RegionCodeEnumTypeWrapper): ...
|
||||||
UNSET: Config.LoRaConfig.RegionCode.ValueType # 0
|
UNSET: Config.LoRaConfig.RegionCode.ValueType # 0
|
||||||
@@ -1280,6 +1478,38 @@ class Config(google.protobuf.message.Message):
|
|||||||
"""
|
"""
|
||||||
Singapore 923mhz
|
Singapore 923mhz
|
||||||
"""
|
"""
|
||||||
|
PH_433: Config.LoRaConfig.RegionCode.ValueType # 19
|
||||||
|
"""
|
||||||
|
Philippines 433mhz
|
||||||
|
"""
|
||||||
|
PH_868: Config.LoRaConfig.RegionCode.ValueType # 20
|
||||||
|
"""
|
||||||
|
Philippines 868mhz
|
||||||
|
"""
|
||||||
|
PH_915: Config.LoRaConfig.RegionCode.ValueType # 21
|
||||||
|
"""
|
||||||
|
Philippines 915mhz
|
||||||
|
"""
|
||||||
|
ANZ_433: Config.LoRaConfig.RegionCode.ValueType # 22
|
||||||
|
"""
|
||||||
|
Australia / New Zealand 433MHz
|
||||||
|
"""
|
||||||
|
KZ_433: Config.LoRaConfig.RegionCode.ValueType # 23
|
||||||
|
"""
|
||||||
|
Kazakhstan 433MHz
|
||||||
|
"""
|
||||||
|
KZ_863: Config.LoRaConfig.RegionCode.ValueType # 24
|
||||||
|
"""
|
||||||
|
Kazakhstan 863MHz
|
||||||
|
"""
|
||||||
|
NP_865: Config.LoRaConfig.RegionCode.ValueType # 25
|
||||||
|
"""
|
||||||
|
Nepal 865MHz
|
||||||
|
"""
|
||||||
|
BR_902: Config.LoRaConfig.RegionCode.ValueType # 26
|
||||||
|
"""
|
||||||
|
Brazil 902MHz
|
||||||
|
"""
|
||||||
|
|
||||||
class _ModemPreset:
|
class _ModemPreset:
|
||||||
ValueType = typing.NewType("ValueType", builtins.int)
|
ValueType = typing.NewType("ValueType", builtins.int)
|
||||||
@@ -1660,6 +1890,7 @@ class Config(google.protobuf.message.Message):
|
|||||||
BLUETOOTH_FIELD_NUMBER: builtins.int
|
BLUETOOTH_FIELD_NUMBER: builtins.int
|
||||||
SECURITY_FIELD_NUMBER: builtins.int
|
SECURITY_FIELD_NUMBER: builtins.int
|
||||||
SESSIONKEY_FIELD_NUMBER: builtins.int
|
SESSIONKEY_FIELD_NUMBER: builtins.int
|
||||||
|
DEVICE_UI_FIELD_NUMBER: builtins.int
|
||||||
@property
|
@property
|
||||||
def device(self) -> global___Config.DeviceConfig: ...
|
def device(self) -> global___Config.DeviceConfig: ...
|
||||||
@property
|
@property
|
||||||
@@ -1678,6 +1909,8 @@ class Config(google.protobuf.message.Message):
|
|||||||
def security(self) -> global___Config.SecurityConfig: ...
|
def security(self) -> global___Config.SecurityConfig: ...
|
||||||
@property
|
@property
|
||||||
def sessionkey(self) -> global___Config.SessionkeyConfig: ...
|
def sessionkey(self) -> global___Config.SessionkeyConfig: ...
|
||||||
|
@property
|
||||||
|
def device_ui(self) -> meshtastic.protobuf.device_ui_pb2.DeviceUIConfig: ...
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
@@ -1690,9 +1923,10 @@ class Config(google.protobuf.message.Message):
|
|||||||
bluetooth: global___Config.BluetoothConfig | None = ...,
|
bluetooth: global___Config.BluetoothConfig | None = ...,
|
||||||
security: global___Config.SecurityConfig | None = ...,
|
security: global___Config.SecurityConfig | None = ...,
|
||||||
sessionkey: global___Config.SessionkeyConfig | None = ...,
|
sessionkey: global___Config.SessionkeyConfig | None = ...,
|
||||||
|
device_ui: meshtastic.protobuf.device_ui_pb2.DeviceUIConfig | None = ...,
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
def HasField(self, field_name: typing.Literal["bluetooth", b"bluetooth", "device", b"device", "display", b"display", "lora", b"lora", "network", b"network", "payload_variant", b"payload_variant", "position", b"position", "power", b"power", "security", b"security", "sessionkey", b"sessionkey"]) -> builtins.bool: ...
|
def HasField(self, field_name: typing.Literal["bluetooth", b"bluetooth", "device", b"device", "device_ui", b"device_ui", "display", b"display", "lora", b"lora", "network", b"network", "payload_variant", b"payload_variant", "position", b"position", "power", b"power", "security", b"security", "sessionkey", b"sessionkey"]) -> builtins.bool: ...
|
||||||
def ClearField(self, field_name: typing.Literal["bluetooth", b"bluetooth", "device", b"device", "display", b"display", "lora", b"lora", "network", b"network", "payload_variant", b"payload_variant", "position", b"position", "power", b"power", "security", b"security", "sessionkey", b"sessionkey"]) -> None: ...
|
def ClearField(self, field_name: typing.Literal["bluetooth", b"bluetooth", "device", b"device", "device_ui", b"device_ui", "display", b"display", "lora", b"lora", "network", b"network", "payload_variant", b"payload_variant", "position", b"position", "power", b"power", "security", b"security", "sessionkey", b"sessionkey"]) -> None: ...
|
||||||
def WhichOneof(self, oneof_group: typing.Literal["payload_variant", b"payload_variant"]) -> typing.Literal["device", "position", "power", "network", "display", "lora", "bluetooth", "security", "sessionkey"] | None: ...
|
def WhichOneof(self, oneof_group: typing.Literal["payload_variant", b"payload_variant"]) -> typing.Literal["device", "position", "power", "network", "display", "lora", "bluetooth", "security", "sessionkey", "device_ui"] | None: ...
|
||||||
|
|
||||||
global___Config = Config
|
global___Config = Config
|
||||||
|
|||||||
40
meshtastic/protobuf/device_ui_pb2.py
generated
Normal file
40
meshtastic/protobuf/device_ui_pb2.py
generated
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
# source: meshtastic/protobuf/device_ui.proto
|
||||||
|
"""Generated protocol buffer code."""
|
||||||
|
from google.protobuf import descriptor as _descriptor
|
||||||
|
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||||
|
from google.protobuf import symbol_database as _symbol_database
|
||||||
|
from google.protobuf.internal import builder as _builder
|
||||||
|
# @@protoc_insertion_point(imports)
|
||||||
|
|
||||||
|
_sym_db = _symbol_database.Default()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n#meshtastic/protobuf/device_ui.proto\x12\x13meshtastic.protobuf\"\xda\x04\n\x0e\x44\x65viceUIConfig\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x19\n\x11screen_brightness\x18\x02 \x01(\r\x12\x16\n\x0escreen_timeout\x18\x03 \x01(\r\x12\x13\n\x0bscreen_lock\x18\x04 \x01(\x08\x12\x15\n\rsettings_lock\x18\x05 \x01(\x08\x12\x10\n\x08pin_code\x18\x06 \x01(\r\x12)\n\x05theme\x18\x07 \x01(\x0e\x32\x1a.meshtastic.protobuf.Theme\x12\x15\n\ralert_enabled\x18\x08 \x01(\x08\x12\x16\n\x0e\x62\x61nner_enabled\x18\t \x01(\x08\x12\x14\n\x0cring_tone_id\x18\n \x01(\r\x12/\n\x08language\x18\x0b \x01(\x0e\x32\x1d.meshtastic.protobuf.Language\x12\x34\n\x0bnode_filter\x18\x0c \x01(\x0b\x32\x1f.meshtastic.protobuf.NodeFilter\x12:\n\x0enode_highlight\x18\r \x01(\x0b\x32\".meshtastic.protobuf.NodeHighlight\x12\x18\n\x10\x63\x61libration_data\x18\x0e \x01(\x0c\x12*\n\x08map_data\x18\x0f \x01(\x0b\x32\x18.meshtastic.protobuf.Map\x12\x36\n\x0c\x63ompass_mode\x18\x10 \x01(\x0e\x32 .meshtastic.protobuf.CompassMode\x12\x18\n\x10screen_rgb_color\x18\x11 \x01(\r\x12\x1b\n\x13is_clockface_analog\x18\x12 \x01(\x08\"\xa7\x01\n\nNodeFilter\x12\x16\n\x0eunknown_switch\x18\x01 \x01(\x08\x12\x16\n\x0eoffline_switch\x18\x02 \x01(\x08\x12\x19\n\x11public_key_switch\x18\x03 \x01(\x08\x12\x11\n\thops_away\x18\x04 \x01(\x05\x12\x17\n\x0fposition_switch\x18\x05 \x01(\x08\x12\x11\n\tnode_name\x18\x06 \x01(\t\x12\x0f\n\x07\x63hannel\x18\x07 \x01(\x05\"~\n\rNodeHighlight\x12\x13\n\x0b\x63hat_switch\x18\x01 \x01(\x08\x12\x17\n\x0fposition_switch\x18\x02 \x01(\x08\x12\x18\n\x10telemetry_switch\x18\x03 \x01(\x08\x12\x12\n\niaq_switch\x18\x04 \x01(\x08\x12\x11\n\tnode_name\x18\x05 \x01(\t\"=\n\x08GeoPoint\x12\x0c\n\x04zoom\x18\x01 \x01(\x05\x12\x10\n\x08latitude\x18\x02 \x01(\x05\x12\x11\n\tlongitude\x18\x03 \x01(\x05\"U\n\x03Map\x12+\n\x04home\x18\x01 \x01(\x0b\x32\x1d.meshtastic.protobuf.GeoPoint\x12\r\n\x05style\x18\x02 \x01(\t\x12\x12\n\nfollow_gps\x18\x03 \x01(\x08*>\n\x0b\x43ompassMode\x12\x0b\n\x07\x44YNAMIC\x10\x00\x12\x0e\n\nFIXED_RING\x10\x01\x12\x12\n\x0e\x46REEZE_HEADING\x10\x02*%\n\x05Theme\x12\x08\n\x04\x44\x41RK\x10\x00\x12\t\n\x05LIGHT\x10\x01\x12\x07\n\x03RED\x10\x02*\xa9\x02\n\x08Language\x12\x0b\n\x07\x45NGLISH\x10\x00\x12\n\n\x06\x46RENCH\x10\x01\x12\n\n\x06GERMAN\x10\x02\x12\x0b\n\x07ITALIAN\x10\x03\x12\x0e\n\nPORTUGUESE\x10\x04\x12\x0b\n\x07SPANISH\x10\x05\x12\x0b\n\x07SWEDISH\x10\x06\x12\x0b\n\x07\x46INNISH\x10\x07\x12\n\n\x06POLISH\x10\x08\x12\x0b\n\x07TURKISH\x10\t\x12\x0b\n\x07SERBIAN\x10\n\x12\x0b\n\x07RUSSIAN\x10\x0b\x12\t\n\x05\x44UTCH\x10\x0c\x12\t\n\x05GREEK\x10\r\x12\r\n\tNORWEGIAN\x10\x0e\x12\r\n\tSLOVENIAN\x10\x0f\x12\r\n\tUKRAINIAN\x10\x10\x12\r\n\tBULGARIAN\x10\x11\x12\x16\n\x12SIMPLIFIED_CHINESE\x10\x1e\x12\x17\n\x13TRADITIONAL_CHINESE\x10\x1f\x42\x63\n\x13\x63om.geeksville.meshB\x0e\x44\x65viceUIProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||||
|
|
||||||
|
_globals = globals()
|
||||||
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||||
|
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.device_ui_pb2', _globals)
|
||||||
|
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||||
|
DESCRIPTOR._options = None
|
||||||
|
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\016DeviceUIProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
|
||||||
|
_globals['_COMPASSMODE']._serialized_start=1113
|
||||||
|
_globals['_COMPASSMODE']._serialized_end=1175
|
||||||
|
_globals['_THEME']._serialized_start=1177
|
||||||
|
_globals['_THEME']._serialized_end=1214
|
||||||
|
_globals['_LANGUAGE']._serialized_start=1217
|
||||||
|
_globals['_LANGUAGE']._serialized_end=1514
|
||||||
|
_globals['_DEVICEUICONFIG']._serialized_start=61
|
||||||
|
_globals['_DEVICEUICONFIG']._serialized_end=663
|
||||||
|
_globals['_NODEFILTER']._serialized_start=666
|
||||||
|
_globals['_NODEFILTER']._serialized_end=833
|
||||||
|
_globals['_NODEHIGHLIGHT']._serialized_start=835
|
||||||
|
_globals['_NODEHIGHLIGHT']._serialized_end=961
|
||||||
|
_globals['_GEOPOINT']._serialized_start=963
|
||||||
|
_globals['_GEOPOINT']._serialized_end=1024
|
||||||
|
_globals['_MAP']._serialized_start=1026
|
||||||
|
_globals['_MAP']._serialized_end=1111
|
||||||
|
# @@protoc_insertion_point(module_scope)
|
||||||
542
meshtastic/protobuf/device_ui_pb2.pyi
generated
Normal file
542
meshtastic/protobuf/device_ui_pb2.pyi
generated
Normal file
@@ -0,0 +1,542 @@
|
|||||||
|
"""
|
||||||
|
@generated by mypy-protobuf. Do not edit manually!
|
||||||
|
isort:skip_file
|
||||||
|
"""
|
||||||
|
|
||||||
|
import builtins
|
||||||
|
import google.protobuf.descriptor
|
||||||
|
import google.protobuf.internal.enum_type_wrapper
|
||||||
|
import google.protobuf.message
|
||||||
|
import sys
|
||||||
|
import typing
|
||||||
|
|
||||||
|
if sys.version_info >= (3, 10):
|
||||||
|
import typing as typing_extensions
|
||||||
|
else:
|
||||||
|
import typing_extensions
|
||||||
|
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
|
||||||
|
|
||||||
|
class _CompassMode:
|
||||||
|
ValueType = typing.NewType("ValueType", builtins.int)
|
||||||
|
V: typing_extensions.TypeAlias = ValueType
|
||||||
|
|
||||||
|
class _CompassModeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_CompassMode.ValueType], builtins.type):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
|
||||||
|
DYNAMIC: _CompassMode.ValueType # 0
|
||||||
|
"""
|
||||||
|
Compass with dynamic ring and heading
|
||||||
|
"""
|
||||||
|
FIXED_RING: _CompassMode.ValueType # 1
|
||||||
|
"""
|
||||||
|
Compass with fixed ring and heading
|
||||||
|
"""
|
||||||
|
FREEZE_HEADING: _CompassMode.ValueType # 2
|
||||||
|
"""
|
||||||
|
Compass with heading and freeze option
|
||||||
|
"""
|
||||||
|
|
||||||
|
class CompassMode(_CompassMode, metaclass=_CompassModeEnumTypeWrapper): ...
|
||||||
|
|
||||||
|
DYNAMIC: CompassMode.ValueType # 0
|
||||||
|
"""
|
||||||
|
Compass with dynamic ring and heading
|
||||||
|
"""
|
||||||
|
FIXED_RING: CompassMode.ValueType # 1
|
||||||
|
"""
|
||||||
|
Compass with fixed ring and heading
|
||||||
|
"""
|
||||||
|
FREEZE_HEADING: CompassMode.ValueType # 2
|
||||||
|
"""
|
||||||
|
Compass with heading and freeze option
|
||||||
|
"""
|
||||||
|
global___CompassMode = CompassMode
|
||||||
|
|
||||||
|
class _Theme:
|
||||||
|
ValueType = typing.NewType("ValueType", builtins.int)
|
||||||
|
V: typing_extensions.TypeAlias = ValueType
|
||||||
|
|
||||||
|
class _ThemeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_Theme.ValueType], builtins.type):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
|
||||||
|
DARK: _Theme.ValueType # 0
|
||||||
|
"""
|
||||||
|
Dark
|
||||||
|
"""
|
||||||
|
LIGHT: _Theme.ValueType # 1
|
||||||
|
"""
|
||||||
|
Light
|
||||||
|
"""
|
||||||
|
RED: _Theme.ValueType # 2
|
||||||
|
"""
|
||||||
|
Red
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Theme(_Theme, metaclass=_ThemeEnumTypeWrapper): ...
|
||||||
|
|
||||||
|
DARK: Theme.ValueType # 0
|
||||||
|
"""
|
||||||
|
Dark
|
||||||
|
"""
|
||||||
|
LIGHT: Theme.ValueType # 1
|
||||||
|
"""
|
||||||
|
Light
|
||||||
|
"""
|
||||||
|
RED: Theme.ValueType # 2
|
||||||
|
"""
|
||||||
|
Red
|
||||||
|
"""
|
||||||
|
global___Theme = Theme
|
||||||
|
|
||||||
|
class _Language:
|
||||||
|
ValueType = typing.NewType("ValueType", builtins.int)
|
||||||
|
V: typing_extensions.TypeAlias = ValueType
|
||||||
|
|
||||||
|
class _LanguageEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_Language.ValueType], builtins.type):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
|
||||||
|
ENGLISH: _Language.ValueType # 0
|
||||||
|
"""
|
||||||
|
English
|
||||||
|
"""
|
||||||
|
FRENCH: _Language.ValueType # 1
|
||||||
|
"""
|
||||||
|
French
|
||||||
|
"""
|
||||||
|
GERMAN: _Language.ValueType # 2
|
||||||
|
"""
|
||||||
|
German
|
||||||
|
"""
|
||||||
|
ITALIAN: _Language.ValueType # 3
|
||||||
|
"""
|
||||||
|
Italian
|
||||||
|
"""
|
||||||
|
PORTUGUESE: _Language.ValueType # 4
|
||||||
|
"""
|
||||||
|
Portuguese
|
||||||
|
"""
|
||||||
|
SPANISH: _Language.ValueType # 5
|
||||||
|
"""
|
||||||
|
Spanish
|
||||||
|
"""
|
||||||
|
SWEDISH: _Language.ValueType # 6
|
||||||
|
"""
|
||||||
|
Swedish
|
||||||
|
"""
|
||||||
|
FINNISH: _Language.ValueType # 7
|
||||||
|
"""
|
||||||
|
Finnish
|
||||||
|
"""
|
||||||
|
POLISH: _Language.ValueType # 8
|
||||||
|
"""
|
||||||
|
Polish
|
||||||
|
"""
|
||||||
|
TURKISH: _Language.ValueType # 9
|
||||||
|
"""
|
||||||
|
Turkish
|
||||||
|
"""
|
||||||
|
SERBIAN: _Language.ValueType # 10
|
||||||
|
"""
|
||||||
|
Serbian
|
||||||
|
"""
|
||||||
|
RUSSIAN: _Language.ValueType # 11
|
||||||
|
"""
|
||||||
|
Russian
|
||||||
|
"""
|
||||||
|
DUTCH: _Language.ValueType # 12
|
||||||
|
"""
|
||||||
|
Dutch
|
||||||
|
"""
|
||||||
|
GREEK: _Language.ValueType # 13
|
||||||
|
"""
|
||||||
|
Greek
|
||||||
|
"""
|
||||||
|
NORWEGIAN: _Language.ValueType # 14
|
||||||
|
"""
|
||||||
|
Norwegian
|
||||||
|
"""
|
||||||
|
SLOVENIAN: _Language.ValueType # 15
|
||||||
|
"""
|
||||||
|
Slovenian
|
||||||
|
"""
|
||||||
|
UKRAINIAN: _Language.ValueType # 16
|
||||||
|
"""
|
||||||
|
Ukrainian
|
||||||
|
"""
|
||||||
|
BULGARIAN: _Language.ValueType # 17
|
||||||
|
"""
|
||||||
|
Bulgarian
|
||||||
|
"""
|
||||||
|
SIMPLIFIED_CHINESE: _Language.ValueType # 30
|
||||||
|
"""
|
||||||
|
Simplified Chinese (experimental)
|
||||||
|
"""
|
||||||
|
TRADITIONAL_CHINESE: _Language.ValueType # 31
|
||||||
|
"""
|
||||||
|
Traditional Chinese (experimental)
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Language(_Language, metaclass=_LanguageEnumTypeWrapper):
|
||||||
|
"""
|
||||||
|
Localization
|
||||||
|
"""
|
||||||
|
|
||||||
|
ENGLISH: Language.ValueType # 0
|
||||||
|
"""
|
||||||
|
English
|
||||||
|
"""
|
||||||
|
FRENCH: Language.ValueType # 1
|
||||||
|
"""
|
||||||
|
French
|
||||||
|
"""
|
||||||
|
GERMAN: Language.ValueType # 2
|
||||||
|
"""
|
||||||
|
German
|
||||||
|
"""
|
||||||
|
ITALIAN: Language.ValueType # 3
|
||||||
|
"""
|
||||||
|
Italian
|
||||||
|
"""
|
||||||
|
PORTUGUESE: Language.ValueType # 4
|
||||||
|
"""
|
||||||
|
Portuguese
|
||||||
|
"""
|
||||||
|
SPANISH: Language.ValueType # 5
|
||||||
|
"""
|
||||||
|
Spanish
|
||||||
|
"""
|
||||||
|
SWEDISH: Language.ValueType # 6
|
||||||
|
"""
|
||||||
|
Swedish
|
||||||
|
"""
|
||||||
|
FINNISH: Language.ValueType # 7
|
||||||
|
"""
|
||||||
|
Finnish
|
||||||
|
"""
|
||||||
|
POLISH: Language.ValueType # 8
|
||||||
|
"""
|
||||||
|
Polish
|
||||||
|
"""
|
||||||
|
TURKISH: Language.ValueType # 9
|
||||||
|
"""
|
||||||
|
Turkish
|
||||||
|
"""
|
||||||
|
SERBIAN: Language.ValueType # 10
|
||||||
|
"""
|
||||||
|
Serbian
|
||||||
|
"""
|
||||||
|
RUSSIAN: Language.ValueType # 11
|
||||||
|
"""
|
||||||
|
Russian
|
||||||
|
"""
|
||||||
|
DUTCH: Language.ValueType # 12
|
||||||
|
"""
|
||||||
|
Dutch
|
||||||
|
"""
|
||||||
|
GREEK: Language.ValueType # 13
|
||||||
|
"""
|
||||||
|
Greek
|
||||||
|
"""
|
||||||
|
NORWEGIAN: Language.ValueType # 14
|
||||||
|
"""
|
||||||
|
Norwegian
|
||||||
|
"""
|
||||||
|
SLOVENIAN: Language.ValueType # 15
|
||||||
|
"""
|
||||||
|
Slovenian
|
||||||
|
"""
|
||||||
|
UKRAINIAN: Language.ValueType # 16
|
||||||
|
"""
|
||||||
|
Ukrainian
|
||||||
|
"""
|
||||||
|
BULGARIAN: Language.ValueType # 17
|
||||||
|
"""
|
||||||
|
Bulgarian
|
||||||
|
"""
|
||||||
|
SIMPLIFIED_CHINESE: Language.ValueType # 30
|
||||||
|
"""
|
||||||
|
Simplified Chinese (experimental)
|
||||||
|
"""
|
||||||
|
TRADITIONAL_CHINESE: Language.ValueType # 31
|
||||||
|
"""
|
||||||
|
Traditional Chinese (experimental)
|
||||||
|
"""
|
||||||
|
global___Language = Language
|
||||||
|
|
||||||
|
@typing.final
|
||||||
|
class DeviceUIConfig(google.protobuf.message.Message):
|
||||||
|
"""
|
||||||
|
Protobuf structures for device-ui persistency
|
||||||
|
"""
|
||||||
|
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||||
|
|
||||||
|
VERSION_FIELD_NUMBER: builtins.int
|
||||||
|
SCREEN_BRIGHTNESS_FIELD_NUMBER: builtins.int
|
||||||
|
SCREEN_TIMEOUT_FIELD_NUMBER: builtins.int
|
||||||
|
SCREEN_LOCK_FIELD_NUMBER: builtins.int
|
||||||
|
SETTINGS_LOCK_FIELD_NUMBER: builtins.int
|
||||||
|
PIN_CODE_FIELD_NUMBER: builtins.int
|
||||||
|
THEME_FIELD_NUMBER: builtins.int
|
||||||
|
ALERT_ENABLED_FIELD_NUMBER: builtins.int
|
||||||
|
BANNER_ENABLED_FIELD_NUMBER: builtins.int
|
||||||
|
RING_TONE_ID_FIELD_NUMBER: builtins.int
|
||||||
|
LANGUAGE_FIELD_NUMBER: builtins.int
|
||||||
|
NODE_FILTER_FIELD_NUMBER: builtins.int
|
||||||
|
NODE_HIGHLIGHT_FIELD_NUMBER: builtins.int
|
||||||
|
CALIBRATION_DATA_FIELD_NUMBER: builtins.int
|
||||||
|
MAP_DATA_FIELD_NUMBER: builtins.int
|
||||||
|
COMPASS_MODE_FIELD_NUMBER: builtins.int
|
||||||
|
SCREEN_RGB_COLOR_FIELD_NUMBER: builtins.int
|
||||||
|
IS_CLOCKFACE_ANALOG_FIELD_NUMBER: builtins.int
|
||||||
|
version: builtins.int
|
||||||
|
"""
|
||||||
|
A version integer used to invalidate saved files when we make incompatible changes.
|
||||||
|
"""
|
||||||
|
screen_brightness: builtins.int
|
||||||
|
"""
|
||||||
|
TFT display brightness 1..255
|
||||||
|
"""
|
||||||
|
screen_timeout: builtins.int
|
||||||
|
"""
|
||||||
|
Screen timeout 0..900
|
||||||
|
"""
|
||||||
|
screen_lock: builtins.bool
|
||||||
|
"""
|
||||||
|
Screen/Settings lock enabled
|
||||||
|
"""
|
||||||
|
settings_lock: builtins.bool
|
||||||
|
pin_code: builtins.int
|
||||||
|
theme: global___Theme.ValueType
|
||||||
|
"""
|
||||||
|
Color theme
|
||||||
|
"""
|
||||||
|
alert_enabled: builtins.bool
|
||||||
|
"""
|
||||||
|
Audible message, banner and ring tone
|
||||||
|
"""
|
||||||
|
banner_enabled: builtins.bool
|
||||||
|
ring_tone_id: builtins.int
|
||||||
|
language: global___Language.ValueType
|
||||||
|
"""
|
||||||
|
Localization
|
||||||
|
"""
|
||||||
|
calibration_data: builtins.bytes
|
||||||
|
"""
|
||||||
|
8 integers for screen calibration data
|
||||||
|
"""
|
||||||
|
compass_mode: global___CompassMode.ValueType
|
||||||
|
"""
|
||||||
|
Compass mode
|
||||||
|
"""
|
||||||
|
screen_rgb_color: builtins.int
|
||||||
|
"""
|
||||||
|
RGB color for BaseUI
|
||||||
|
0xRRGGBB format, e.g. 0xFF0000 for red
|
||||||
|
"""
|
||||||
|
is_clockface_analog: builtins.bool
|
||||||
|
"""
|
||||||
|
Clockface analog style
|
||||||
|
true for analog clockface, false for digital clockface
|
||||||
|
"""
|
||||||
|
@property
|
||||||
|
def node_filter(self) -> global___NodeFilter:
|
||||||
|
"""
|
||||||
|
Node list filter
|
||||||
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def node_highlight(self) -> global___NodeHighlight:
|
||||||
|
"""
|
||||||
|
Node list highlightening
|
||||||
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def map_data(self) -> global___Map:
|
||||||
|
"""
|
||||||
|
Map related data
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
version: builtins.int = ...,
|
||||||
|
screen_brightness: builtins.int = ...,
|
||||||
|
screen_timeout: builtins.int = ...,
|
||||||
|
screen_lock: builtins.bool = ...,
|
||||||
|
settings_lock: builtins.bool = ...,
|
||||||
|
pin_code: builtins.int = ...,
|
||||||
|
theme: global___Theme.ValueType = ...,
|
||||||
|
alert_enabled: builtins.bool = ...,
|
||||||
|
banner_enabled: builtins.bool = ...,
|
||||||
|
ring_tone_id: builtins.int = ...,
|
||||||
|
language: global___Language.ValueType = ...,
|
||||||
|
node_filter: global___NodeFilter | None = ...,
|
||||||
|
node_highlight: global___NodeHighlight | None = ...,
|
||||||
|
calibration_data: builtins.bytes = ...,
|
||||||
|
map_data: global___Map | None = ...,
|
||||||
|
compass_mode: global___CompassMode.ValueType = ...,
|
||||||
|
screen_rgb_color: builtins.int = ...,
|
||||||
|
is_clockface_analog: builtins.bool = ...,
|
||||||
|
) -> None: ...
|
||||||
|
def HasField(self, field_name: typing.Literal["map_data", b"map_data", "node_filter", b"node_filter", "node_highlight", b"node_highlight"]) -> builtins.bool: ...
|
||||||
|
def ClearField(self, field_name: typing.Literal["alert_enabled", b"alert_enabled", "banner_enabled", b"banner_enabled", "calibration_data", b"calibration_data", "compass_mode", b"compass_mode", "is_clockface_analog", b"is_clockface_analog", "language", b"language", "map_data", b"map_data", "node_filter", b"node_filter", "node_highlight", b"node_highlight", "pin_code", b"pin_code", "ring_tone_id", b"ring_tone_id", "screen_brightness", b"screen_brightness", "screen_lock", b"screen_lock", "screen_rgb_color", b"screen_rgb_color", "screen_timeout", b"screen_timeout", "settings_lock", b"settings_lock", "theme", b"theme", "version", b"version"]) -> None: ...
|
||||||
|
|
||||||
|
global___DeviceUIConfig = DeviceUIConfig
|
||||||
|
|
||||||
|
@typing.final
|
||||||
|
class NodeFilter(google.protobuf.message.Message):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||||
|
|
||||||
|
UNKNOWN_SWITCH_FIELD_NUMBER: builtins.int
|
||||||
|
OFFLINE_SWITCH_FIELD_NUMBER: builtins.int
|
||||||
|
PUBLIC_KEY_SWITCH_FIELD_NUMBER: builtins.int
|
||||||
|
HOPS_AWAY_FIELD_NUMBER: builtins.int
|
||||||
|
POSITION_SWITCH_FIELD_NUMBER: builtins.int
|
||||||
|
NODE_NAME_FIELD_NUMBER: builtins.int
|
||||||
|
CHANNEL_FIELD_NUMBER: builtins.int
|
||||||
|
unknown_switch: builtins.bool
|
||||||
|
"""
|
||||||
|
Filter unknown nodes
|
||||||
|
"""
|
||||||
|
offline_switch: builtins.bool
|
||||||
|
"""
|
||||||
|
Filter offline nodes
|
||||||
|
"""
|
||||||
|
public_key_switch: builtins.bool
|
||||||
|
"""
|
||||||
|
Filter nodes w/o public key
|
||||||
|
"""
|
||||||
|
hops_away: builtins.int
|
||||||
|
"""
|
||||||
|
Filter based on hops away
|
||||||
|
"""
|
||||||
|
position_switch: builtins.bool
|
||||||
|
"""
|
||||||
|
Filter nodes w/o position
|
||||||
|
"""
|
||||||
|
node_name: builtins.str
|
||||||
|
"""
|
||||||
|
Filter nodes by matching name string
|
||||||
|
"""
|
||||||
|
channel: builtins.int
|
||||||
|
"""
|
||||||
|
Filter based on channel
|
||||||
|
"""
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
unknown_switch: builtins.bool = ...,
|
||||||
|
offline_switch: builtins.bool = ...,
|
||||||
|
public_key_switch: builtins.bool = ...,
|
||||||
|
hops_away: builtins.int = ...,
|
||||||
|
position_switch: builtins.bool = ...,
|
||||||
|
node_name: builtins.str = ...,
|
||||||
|
channel: builtins.int = ...,
|
||||||
|
) -> None: ...
|
||||||
|
def ClearField(self, field_name: typing.Literal["channel", b"channel", "hops_away", b"hops_away", "node_name", b"node_name", "offline_switch", b"offline_switch", "position_switch", b"position_switch", "public_key_switch", b"public_key_switch", "unknown_switch", b"unknown_switch"]) -> None: ...
|
||||||
|
|
||||||
|
global___NodeFilter = NodeFilter
|
||||||
|
|
||||||
|
@typing.final
|
||||||
|
class NodeHighlight(google.protobuf.message.Message):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||||
|
|
||||||
|
CHAT_SWITCH_FIELD_NUMBER: builtins.int
|
||||||
|
POSITION_SWITCH_FIELD_NUMBER: builtins.int
|
||||||
|
TELEMETRY_SWITCH_FIELD_NUMBER: builtins.int
|
||||||
|
IAQ_SWITCH_FIELD_NUMBER: builtins.int
|
||||||
|
NODE_NAME_FIELD_NUMBER: builtins.int
|
||||||
|
chat_switch: builtins.bool
|
||||||
|
"""
|
||||||
|
Hightlight nodes w/ active chat
|
||||||
|
"""
|
||||||
|
position_switch: builtins.bool
|
||||||
|
"""
|
||||||
|
Highlight nodes w/ position
|
||||||
|
"""
|
||||||
|
telemetry_switch: builtins.bool
|
||||||
|
"""
|
||||||
|
Highlight nodes w/ telemetry data
|
||||||
|
"""
|
||||||
|
iaq_switch: builtins.bool
|
||||||
|
"""
|
||||||
|
Highlight nodes w/ iaq data
|
||||||
|
"""
|
||||||
|
node_name: builtins.str
|
||||||
|
"""
|
||||||
|
Highlight nodes by matching name string
|
||||||
|
"""
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
chat_switch: builtins.bool = ...,
|
||||||
|
position_switch: builtins.bool = ...,
|
||||||
|
telemetry_switch: builtins.bool = ...,
|
||||||
|
iaq_switch: builtins.bool = ...,
|
||||||
|
node_name: builtins.str = ...,
|
||||||
|
) -> None: ...
|
||||||
|
def ClearField(self, field_name: typing.Literal["chat_switch", b"chat_switch", "iaq_switch", b"iaq_switch", "node_name", b"node_name", "position_switch", b"position_switch", "telemetry_switch", b"telemetry_switch"]) -> None: ...
|
||||||
|
|
||||||
|
global___NodeHighlight = NodeHighlight
|
||||||
|
|
||||||
|
@typing.final
|
||||||
|
class GeoPoint(google.protobuf.message.Message):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||||
|
|
||||||
|
ZOOM_FIELD_NUMBER: builtins.int
|
||||||
|
LATITUDE_FIELD_NUMBER: builtins.int
|
||||||
|
LONGITUDE_FIELD_NUMBER: builtins.int
|
||||||
|
zoom: builtins.int
|
||||||
|
"""
|
||||||
|
Zoom level
|
||||||
|
"""
|
||||||
|
latitude: builtins.int
|
||||||
|
"""
|
||||||
|
Coordinate: latitude
|
||||||
|
"""
|
||||||
|
longitude: builtins.int
|
||||||
|
"""
|
||||||
|
Coordinate: longitude
|
||||||
|
"""
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
zoom: builtins.int = ...,
|
||||||
|
latitude: builtins.int = ...,
|
||||||
|
longitude: builtins.int = ...,
|
||||||
|
) -> None: ...
|
||||||
|
def ClearField(self, field_name: typing.Literal["latitude", b"latitude", "longitude", b"longitude", "zoom", b"zoom"]) -> None: ...
|
||||||
|
|
||||||
|
global___GeoPoint = GeoPoint
|
||||||
|
|
||||||
|
@typing.final
|
||||||
|
class Map(google.protobuf.message.Message):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||||
|
|
||||||
|
HOME_FIELD_NUMBER: builtins.int
|
||||||
|
STYLE_FIELD_NUMBER: builtins.int
|
||||||
|
FOLLOW_GPS_FIELD_NUMBER: builtins.int
|
||||||
|
style: builtins.str
|
||||||
|
"""
|
||||||
|
Map tile style
|
||||||
|
"""
|
||||||
|
follow_gps: builtins.bool
|
||||||
|
"""
|
||||||
|
Map scroll follows GPS
|
||||||
|
"""
|
||||||
|
@property
|
||||||
|
def home(self) -> global___GeoPoint:
|
||||||
|
"""
|
||||||
|
Home coordinates
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
home: global___GeoPoint | None = ...,
|
||||||
|
style: builtins.str = ...,
|
||||||
|
follow_gps: builtins.bool = ...,
|
||||||
|
) -> None: ...
|
||||||
|
def HasField(self, field_name: typing.Literal["home", b"home"]) -> builtins.bool: ...
|
||||||
|
def ClearField(self, field_name: typing.Literal["follow_gps", b"follow_gps", "home", b"home", "style", b"style"]) -> None: ...
|
||||||
|
|
||||||
|
global___Map = Map
|
||||||
40
meshtastic/protobuf/deviceonly_pb2.py
generated
40
meshtastic/protobuf/deviceonly_pb2.py
generated
@@ -12,14 +12,14 @@ _sym_db = _symbol_database.Default()
|
|||||||
|
|
||||||
|
|
||||||
from meshtastic.protobuf import channel_pb2 as meshtastic_dot_protobuf_dot_channel__pb2
|
from meshtastic.protobuf import channel_pb2 as meshtastic_dot_protobuf_dot_channel__pb2
|
||||||
|
from meshtastic.protobuf import config_pb2 as meshtastic_dot_protobuf_dot_config__pb2
|
||||||
from meshtastic.protobuf import localonly_pb2 as meshtastic_dot_protobuf_dot_localonly__pb2
|
from meshtastic.protobuf import localonly_pb2 as meshtastic_dot_protobuf_dot_localonly__pb2
|
||||||
from meshtastic.protobuf import mesh_pb2 as meshtastic_dot_protobuf_dot_mesh__pb2
|
from meshtastic.protobuf import mesh_pb2 as meshtastic_dot_protobuf_dot_mesh__pb2
|
||||||
from meshtastic.protobuf import telemetry_pb2 as meshtastic_dot_protobuf_dot_telemetry__pb2
|
from meshtastic.protobuf import telemetry_pb2 as meshtastic_dot_protobuf_dot_telemetry__pb2
|
||||||
from meshtastic.protobuf import config_pb2 as meshtastic_dot_protobuf_dot_config__pb2
|
from meshtastic.protobuf import nanopb_pb2 as meshtastic_dot_protobuf_dot_nanopb__pb2
|
||||||
import nanopb_pb2 as nanopb__pb2
|
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n$meshtastic/protobuf/deviceonly.proto\x12\x13meshtastic.protobuf\x1a!meshtastic/protobuf/channel.proto\x1a#meshtastic/protobuf/localonly.proto\x1a\x1emeshtastic/protobuf/mesh.proto\x1a#meshtastic/protobuf/telemetry.proto\x1a meshtastic/protobuf/config.proto\x1a\x0cnanopb.proto\"\x99\x01\n\x0cPositionLite\x12\x12\n\nlatitude_i\x18\x01 \x01(\x0f\x12\x13\n\x0blongitude_i\x18\x02 \x01(\x0f\x12\x10\n\x08\x61ltitude\x18\x03 \x01(\x05\x12\x0c\n\x04time\x18\x04 \x01(\x07\x12@\n\x0flocation_source\x18\x05 \x01(\x0e\x32\'.meshtastic.protobuf.Position.LocSource\"\xe2\x01\n\x08UserLite\x12\x13\n\x07macaddr\x18\x01 \x01(\x0c\x42\x02\x18\x01\x12\x11\n\tlong_name\x18\x02 \x01(\t\x12\x12\n\nshort_name\x18\x03 \x01(\t\x12\x34\n\x08hw_model\x18\x04 \x01(\x0e\x32\".meshtastic.protobuf.HardwareModel\x12\x13\n\x0bis_licensed\x18\x05 \x01(\x08\x12;\n\x04role\x18\x06 \x01(\x0e\x32-.meshtastic.protobuf.Config.DeviceConfig.Role\x12\x12\n\npublic_key\x18\x07 \x01(\x0c\"\xb8\x02\n\x0cNodeInfoLite\x12\x0b\n\x03num\x18\x01 \x01(\r\x12+\n\x04user\x18\x02 \x01(\x0b\x32\x1d.meshtastic.protobuf.UserLite\x12\x33\n\x08position\x18\x03 \x01(\x0b\x32!.meshtastic.protobuf.PositionLite\x12\x0b\n\x03snr\x18\x04 \x01(\x02\x12\x12\n\nlast_heard\x18\x05 \x01(\x07\x12:\n\x0e\x64\x65vice_metrics\x18\x06 \x01(\x0b\x32\".meshtastic.protobuf.DeviceMetrics\x12\x0f\n\x07\x63hannel\x18\x07 \x01(\r\x12\x10\n\x08via_mqtt\x18\x08 \x01(\x08\x12\x16\n\thops_away\x18\t \x01(\rH\x00\x88\x01\x01\x12\x13\n\x0bis_favorite\x18\n \x01(\x08\x42\x0c\n\n_hops_away\"\x82\x04\n\x0b\x44\x65viceState\x12\x30\n\x07my_node\x18\x02 \x01(\x0b\x32\x1f.meshtastic.protobuf.MyNodeInfo\x12(\n\x05owner\x18\x03 \x01(\x0b\x32\x19.meshtastic.protobuf.User\x12\x36\n\rreceive_queue\x18\x05 \x03(\x0b\x32\x1f.meshtastic.protobuf.MeshPacket\x12\x0f\n\x07version\x18\x08 \x01(\r\x12\x38\n\x0frx_text_message\x18\x07 \x01(\x0b\x32\x1f.meshtastic.protobuf.MeshPacket\x12\x13\n\x07no_save\x18\t \x01(\x08\x42\x02\x18\x01\x12\x15\n\rdid_gps_reset\x18\x0b \x01(\x08\x12\x34\n\x0brx_waypoint\x18\x0c \x01(\x0b\x32\x1f.meshtastic.protobuf.MeshPacket\x12M\n\x19node_remote_hardware_pins\x18\r \x03(\x0b\x32*.meshtastic.protobuf.NodeRemoteHardwarePin\x12\x63\n\x0cnode_db_lite\x18\x0e \x03(\x0b\x32!.meshtastic.protobuf.NodeInfoLiteB*\x92?\'\x92\x01$std::vector<meshtastic_NodeInfoLite>\"N\n\x0b\x43hannelFile\x12.\n\x08\x63hannels\x18\x01 \x03(\x0b\x32\x1c.meshtastic.protobuf.Channel\x12\x0f\n\x07version\x18\x02 \x01(\r\"\xb2\x02\n\x08OEMStore\x12\x16\n\x0eoem_icon_width\x18\x01 \x01(\r\x12\x17\n\x0foem_icon_height\x18\x02 \x01(\r\x12\x15\n\roem_icon_bits\x18\x03 \x01(\x0c\x12\x32\n\x08oem_font\x18\x04 \x01(\x0e\x32 .meshtastic.protobuf.ScreenFonts\x12\x10\n\x08oem_text\x18\x05 \x01(\t\x12\x13\n\x0boem_aes_key\x18\x06 \x01(\x0c\x12:\n\x10oem_local_config\x18\x07 \x01(\x0b\x32 .meshtastic.protobuf.LocalConfig\x12G\n\x17oem_local_module_config\x18\x08 \x01(\x0b\x32&.meshtastic.protobuf.LocalModuleConfig*>\n\x0bScreenFonts\x12\x0e\n\nFONT_SMALL\x10\x00\x12\x0f\n\x0b\x46ONT_MEDIUM\x10\x01\x12\x0e\n\nFONT_LARGE\x10\x02\x42m\n\x13\x63om.geeksville.meshB\nDeviceOnlyZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x92?\x0b\xc2\x01\x08<vector>b\x06proto3')
|
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n$meshtastic/protobuf/deviceonly.proto\x12\x13meshtastic.protobuf\x1a!meshtastic/protobuf/channel.proto\x1a meshtastic/protobuf/config.proto\x1a#meshtastic/protobuf/localonly.proto\x1a\x1emeshtastic/protobuf/mesh.proto\x1a#meshtastic/protobuf/telemetry.proto\x1a meshtastic/protobuf/nanopb.proto\"\x99\x01\n\x0cPositionLite\x12\x12\n\nlatitude_i\x18\x01 \x01(\x0f\x12\x13\n\x0blongitude_i\x18\x02 \x01(\x0f\x12\x10\n\x08\x61ltitude\x18\x03 \x01(\x05\x12\x0c\n\x04time\x18\x04 \x01(\x07\x12@\n\x0flocation_source\x18\x05 \x01(\x0e\x32\'.meshtastic.protobuf.Position.LocSource\"\x94\x02\n\x08UserLite\x12\x13\n\x07macaddr\x18\x01 \x01(\x0c\x42\x02\x18\x01\x12\x11\n\tlong_name\x18\x02 \x01(\t\x12\x12\n\nshort_name\x18\x03 \x01(\t\x12\x34\n\x08hw_model\x18\x04 \x01(\x0e\x32\".meshtastic.protobuf.HardwareModel\x12\x13\n\x0bis_licensed\x18\x05 \x01(\x08\x12;\n\x04role\x18\x06 \x01(\x0e\x32-.meshtastic.protobuf.Config.DeviceConfig.Role\x12\x12\n\npublic_key\x18\x07 \x01(\x0c\x12\x1c\n\x0fis_unmessagable\x18\t \x01(\x08H\x00\x88\x01\x01\x42\x12\n\x10_is_unmessagable\"\xf0\x02\n\x0cNodeInfoLite\x12\x0b\n\x03num\x18\x01 \x01(\r\x12+\n\x04user\x18\x02 \x01(\x0b\x32\x1d.meshtastic.protobuf.UserLite\x12\x33\n\x08position\x18\x03 \x01(\x0b\x32!.meshtastic.protobuf.PositionLite\x12\x0b\n\x03snr\x18\x04 \x01(\x02\x12\x12\n\nlast_heard\x18\x05 \x01(\x07\x12:\n\x0e\x64\x65vice_metrics\x18\x06 \x01(\x0b\x32\".meshtastic.protobuf.DeviceMetrics\x12\x0f\n\x07\x63hannel\x18\x07 \x01(\r\x12\x10\n\x08via_mqtt\x18\x08 \x01(\x08\x12\x16\n\thops_away\x18\t \x01(\rH\x00\x88\x01\x01\x12\x13\n\x0bis_favorite\x18\n \x01(\x08\x12\x12\n\nis_ignored\x18\x0b \x01(\x08\x12\x10\n\x08next_hop\x18\x0c \x01(\r\x12\x10\n\x08\x62itfield\x18\r \x01(\rB\x0c\n\n_hops_away\"\xa1\x03\n\x0b\x44\x65viceState\x12\x30\n\x07my_node\x18\x02 \x01(\x0b\x32\x1f.meshtastic.protobuf.MyNodeInfo\x12(\n\x05owner\x18\x03 \x01(\x0b\x32\x19.meshtastic.protobuf.User\x12\x36\n\rreceive_queue\x18\x05 \x03(\x0b\x32\x1f.meshtastic.protobuf.MeshPacket\x12\x0f\n\x07version\x18\x08 \x01(\r\x12\x38\n\x0frx_text_message\x18\x07 \x01(\x0b\x32\x1f.meshtastic.protobuf.MeshPacket\x12\x13\n\x07no_save\x18\t \x01(\x08\x42\x02\x18\x01\x12\x19\n\rdid_gps_reset\x18\x0b \x01(\x08\x42\x02\x18\x01\x12\x34\n\x0brx_waypoint\x18\x0c \x01(\x0b\x32\x1f.meshtastic.protobuf.MeshPacket\x12M\n\x19node_remote_hardware_pins\x18\r \x03(\x0b\x32*.meshtastic.protobuf.NodeRemoteHardwarePin\"}\n\x0cNodeDatabase\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\\\n\x05nodes\x18\x02 \x03(\x0b\x32!.meshtastic.protobuf.NodeInfoLiteB*\x92?\'\x92\x01$std::vector<meshtastic_NodeInfoLite>\"N\n\x0b\x43hannelFile\x12.\n\x08\x63hannels\x18\x01 \x03(\x0b\x32\x1c.meshtastic.protobuf.Channel\x12\x0f\n\x07version\x18\x02 \x01(\r\"\x86\x02\n\x11\x42\x61\x63kupPreferences\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x11\n\ttimestamp\x18\x02 \x01(\x07\x12\x30\n\x06\x63onfig\x18\x03 \x01(\x0b\x32 .meshtastic.protobuf.LocalConfig\x12=\n\rmodule_config\x18\x04 \x01(\x0b\x32&.meshtastic.protobuf.LocalModuleConfig\x12\x32\n\x08\x63hannels\x18\x05 \x01(\x0b\x32 .meshtastic.protobuf.ChannelFile\x12(\n\x05owner\x18\x06 \x01(\x0b\x32\x19.meshtastic.protobuf.UserBm\n\x13\x63om.geeksville.meshB\nDeviceOnlyZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x92?\x0b\xc2\x01\x08<vector>b\x06proto3')
|
||||||
|
|
||||||
_globals = globals()
|
_globals = globals()
|
||||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||||
@@ -31,20 +31,22 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|||||||
_USERLITE.fields_by_name['macaddr']._serialized_options = b'\030\001'
|
_USERLITE.fields_by_name['macaddr']._serialized_options = b'\030\001'
|
||||||
_DEVICESTATE.fields_by_name['no_save']._options = None
|
_DEVICESTATE.fields_by_name['no_save']._options = None
|
||||||
_DEVICESTATE.fields_by_name['no_save']._serialized_options = b'\030\001'
|
_DEVICESTATE.fields_by_name['no_save']._serialized_options = b'\030\001'
|
||||||
_DEVICESTATE.fields_by_name['node_db_lite']._options = None
|
_DEVICESTATE.fields_by_name['did_gps_reset']._options = None
|
||||||
_DEVICESTATE.fields_by_name['node_db_lite']._serialized_options = b'\222?\'\222\001$std::vector<meshtastic_NodeInfoLite>'
|
_DEVICESTATE.fields_by_name['did_gps_reset']._serialized_options = b'\030\001'
|
||||||
_globals['_SCREENFONTS']._serialized_start=1856
|
_NODEDATABASE.fields_by_name['nodes']._options = None
|
||||||
_globals['_SCREENFONTS']._serialized_end=1918
|
_NODEDATABASE.fields_by_name['nodes']._serialized_options = b'\222?\'\222\001$std::vector<meshtastic_NodeInfoLite>'
|
||||||
_globals['_POSITIONLITE']._serialized_start=251
|
_globals['_POSITIONLITE']._serialized_start=271
|
||||||
_globals['_POSITIONLITE']._serialized_end=404
|
_globals['_POSITIONLITE']._serialized_end=424
|
||||||
_globals['_USERLITE']._serialized_start=407
|
_globals['_USERLITE']._serialized_start=427
|
||||||
_globals['_USERLITE']._serialized_end=633
|
_globals['_USERLITE']._serialized_end=703
|
||||||
_globals['_NODEINFOLITE']._serialized_start=636
|
_globals['_NODEINFOLITE']._serialized_start=706
|
||||||
_globals['_NODEINFOLITE']._serialized_end=948
|
_globals['_NODEINFOLITE']._serialized_end=1074
|
||||||
_globals['_DEVICESTATE']._serialized_start=951
|
_globals['_DEVICESTATE']._serialized_start=1077
|
||||||
_globals['_DEVICESTATE']._serialized_end=1465
|
_globals['_DEVICESTATE']._serialized_end=1494
|
||||||
_globals['_CHANNELFILE']._serialized_start=1467
|
_globals['_NODEDATABASE']._serialized_start=1496
|
||||||
_globals['_CHANNELFILE']._serialized_end=1545
|
_globals['_NODEDATABASE']._serialized_end=1621
|
||||||
_globals['_OEMSTORE']._serialized_start=1548
|
_globals['_CHANNELFILE']._serialized_start=1623
|
||||||
_globals['_OEMSTORE']._serialized_end=1854
|
_globals['_CHANNELFILE']._serialized_end=1701
|
||||||
|
_globals['_BACKUPPREFERENCES']._serialized_start=1704
|
||||||
|
_globals['_BACKUPPREFERENCES']._serialized_end=1966
|
||||||
# @@protoc_insertion_point(module_scope)
|
# @@protoc_insertion_point(module_scope)
|
||||||
|
|||||||
203
meshtastic/protobuf/deviceonly_pb2.pyi
generated
203
meshtastic/protobuf/deviceonly_pb2.pyi
generated
@@ -7,61 +7,16 @@ import builtins
|
|||||||
import collections.abc
|
import collections.abc
|
||||||
import google.protobuf.descriptor
|
import google.protobuf.descriptor
|
||||||
import google.protobuf.internal.containers
|
import google.protobuf.internal.containers
|
||||||
import google.protobuf.internal.enum_type_wrapper
|
|
||||||
import google.protobuf.message
|
import google.protobuf.message
|
||||||
import meshtastic.protobuf.channel_pb2
|
import meshtastic.protobuf.channel_pb2
|
||||||
import meshtastic.protobuf.config_pb2
|
import meshtastic.protobuf.config_pb2
|
||||||
import meshtastic.protobuf.localonly_pb2
|
import meshtastic.protobuf.localonly_pb2
|
||||||
import meshtastic.protobuf.mesh_pb2
|
import meshtastic.protobuf.mesh_pb2
|
||||||
import meshtastic.protobuf.telemetry_pb2
|
import meshtastic.protobuf.telemetry_pb2
|
||||||
import sys
|
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
if sys.version_info >= (3, 10):
|
|
||||||
import typing as typing_extensions
|
|
||||||
else:
|
|
||||||
import typing_extensions
|
|
||||||
|
|
||||||
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
|
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
|
||||||
|
|
||||||
class _ScreenFonts:
|
|
||||||
ValueType = typing.NewType("ValueType", builtins.int)
|
|
||||||
V: typing_extensions.TypeAlias = ValueType
|
|
||||||
|
|
||||||
class _ScreenFontsEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_ScreenFonts.ValueType], builtins.type):
|
|
||||||
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
|
|
||||||
FONT_SMALL: _ScreenFonts.ValueType # 0
|
|
||||||
"""
|
|
||||||
TODO: REPLACE
|
|
||||||
"""
|
|
||||||
FONT_MEDIUM: _ScreenFonts.ValueType # 1
|
|
||||||
"""
|
|
||||||
TODO: REPLACE
|
|
||||||
"""
|
|
||||||
FONT_LARGE: _ScreenFonts.ValueType # 2
|
|
||||||
"""
|
|
||||||
TODO: REPLACE
|
|
||||||
"""
|
|
||||||
|
|
||||||
class ScreenFonts(_ScreenFonts, metaclass=_ScreenFontsEnumTypeWrapper):
|
|
||||||
"""
|
|
||||||
Font sizes for the device screen
|
|
||||||
"""
|
|
||||||
|
|
||||||
FONT_SMALL: ScreenFonts.ValueType # 0
|
|
||||||
"""
|
|
||||||
TODO: REPLACE
|
|
||||||
"""
|
|
||||||
FONT_MEDIUM: ScreenFonts.ValueType # 1
|
|
||||||
"""
|
|
||||||
TODO: REPLACE
|
|
||||||
"""
|
|
||||||
FONT_LARGE: ScreenFonts.ValueType # 2
|
|
||||||
"""
|
|
||||||
TODO: REPLACE
|
|
||||||
"""
|
|
||||||
global___ScreenFonts = ScreenFonts
|
|
||||||
|
|
||||||
@typing.final
|
@typing.final
|
||||||
class PositionLite(google.protobuf.message.Message):
|
class PositionLite(google.protobuf.message.Message):
|
||||||
"""
|
"""
|
||||||
@@ -124,6 +79,7 @@ class UserLite(google.protobuf.message.Message):
|
|||||||
IS_LICENSED_FIELD_NUMBER: builtins.int
|
IS_LICENSED_FIELD_NUMBER: builtins.int
|
||||||
ROLE_FIELD_NUMBER: builtins.int
|
ROLE_FIELD_NUMBER: builtins.int
|
||||||
PUBLIC_KEY_FIELD_NUMBER: builtins.int
|
PUBLIC_KEY_FIELD_NUMBER: builtins.int
|
||||||
|
IS_UNMESSAGABLE_FIELD_NUMBER: builtins.int
|
||||||
macaddr: builtins.bytes
|
macaddr: builtins.bytes
|
||||||
"""
|
"""
|
||||||
This is the addr of the radio.
|
This is the addr of the radio.
|
||||||
@@ -159,6 +115,10 @@ class UserLite(google.protobuf.message.Message):
|
|||||||
The public key of the user's device.
|
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.
|
This is sent out to other nodes on the mesh to allow them to compute a shared secret key.
|
||||||
"""
|
"""
|
||||||
|
is_unmessagable: builtins.bool
|
||||||
|
"""
|
||||||
|
Whether or not the node can be messaged
|
||||||
|
"""
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
@@ -169,8 +129,11 @@ class UserLite(google.protobuf.message.Message):
|
|||||||
is_licensed: builtins.bool = ...,
|
is_licensed: builtins.bool = ...,
|
||||||
role: meshtastic.protobuf.config_pb2.Config.DeviceConfig.Role.ValueType = ...,
|
role: meshtastic.protobuf.config_pb2.Config.DeviceConfig.Role.ValueType = ...,
|
||||||
public_key: builtins.bytes = ...,
|
public_key: builtins.bytes = ...,
|
||||||
|
is_unmessagable: builtins.bool | None = ...,
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
def ClearField(self, field_name: typing.Literal["hw_model", b"hw_model", "is_licensed", b"is_licensed", "long_name", b"long_name", "macaddr", b"macaddr", "public_key", b"public_key", "role", b"role", "short_name", b"short_name"]) -> None: ...
|
def HasField(self, field_name: typing.Literal["_is_unmessagable", b"_is_unmessagable", "is_unmessagable", b"is_unmessagable"]) -> builtins.bool: ...
|
||||||
|
def ClearField(self, field_name: typing.Literal["_is_unmessagable", b"_is_unmessagable", "hw_model", b"hw_model", "is_licensed", b"is_licensed", "is_unmessagable", b"is_unmessagable", "long_name", b"long_name", "macaddr", b"macaddr", "public_key", b"public_key", "role", b"role", "short_name", b"short_name"]) -> None: ...
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_is_unmessagable", b"_is_unmessagable"]) -> typing.Literal["is_unmessagable"] | None: ...
|
||||||
|
|
||||||
global___UserLite = UserLite
|
global___UserLite = UserLite
|
||||||
|
|
||||||
@@ -188,6 +151,9 @@ class NodeInfoLite(google.protobuf.message.Message):
|
|||||||
VIA_MQTT_FIELD_NUMBER: builtins.int
|
VIA_MQTT_FIELD_NUMBER: builtins.int
|
||||||
HOPS_AWAY_FIELD_NUMBER: builtins.int
|
HOPS_AWAY_FIELD_NUMBER: builtins.int
|
||||||
IS_FAVORITE_FIELD_NUMBER: builtins.int
|
IS_FAVORITE_FIELD_NUMBER: builtins.int
|
||||||
|
IS_IGNORED_FIELD_NUMBER: builtins.int
|
||||||
|
NEXT_HOP_FIELD_NUMBER: builtins.int
|
||||||
|
BITFIELD_FIELD_NUMBER: builtins.int
|
||||||
num: builtins.int
|
num: builtins.int
|
||||||
"""
|
"""
|
||||||
The node number
|
The node number
|
||||||
@@ -211,13 +177,27 @@ class NodeInfoLite(google.protobuf.message.Message):
|
|||||||
"""
|
"""
|
||||||
hops_away: builtins.int
|
hops_away: builtins.int
|
||||||
"""
|
"""
|
||||||
Number of hops away from us this node is (0 if adjacent)
|
Number of hops away from us this node is (0 if direct neighbor)
|
||||||
"""
|
"""
|
||||||
is_favorite: builtins.bool
|
is_favorite: builtins.bool
|
||||||
"""
|
"""
|
||||||
True if node is in our favorites list
|
True if node is in our favorites list
|
||||||
Persists between NodeDB internal clean ups
|
Persists between NodeDB internal clean ups
|
||||||
"""
|
"""
|
||||||
|
is_ignored: builtins.bool
|
||||||
|
"""
|
||||||
|
True if node is in our ignored list
|
||||||
|
Persists between NodeDB internal clean ups
|
||||||
|
"""
|
||||||
|
next_hop: builtins.int
|
||||||
|
"""
|
||||||
|
Last byte of the node number of the node that should be used as the next hop to reach this node.
|
||||||
|
"""
|
||||||
|
bitfield: builtins.int
|
||||||
|
"""
|
||||||
|
Bitfield for storing booleans.
|
||||||
|
LSB 0 is_key_manually_verified
|
||||||
|
"""
|
||||||
@property
|
@property
|
||||||
def user(self) -> global___UserLite:
|
def user(self) -> global___UserLite:
|
||||||
"""
|
"""
|
||||||
@@ -250,9 +230,12 @@ class NodeInfoLite(google.protobuf.message.Message):
|
|||||||
via_mqtt: builtins.bool = ...,
|
via_mqtt: builtins.bool = ...,
|
||||||
hops_away: builtins.int | None = ...,
|
hops_away: builtins.int | None = ...,
|
||||||
is_favorite: builtins.bool = ...,
|
is_favorite: builtins.bool = ...,
|
||||||
|
is_ignored: builtins.bool = ...,
|
||||||
|
next_hop: builtins.int = ...,
|
||||||
|
bitfield: builtins.int = ...,
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
def HasField(self, field_name: typing.Literal["_hops_away", b"_hops_away", "device_metrics", b"device_metrics", "hops_away", b"hops_away", "position", b"position", "user", b"user"]) -> builtins.bool: ...
|
def HasField(self, field_name: typing.Literal["_hops_away", b"_hops_away", "device_metrics", b"device_metrics", "hops_away", b"hops_away", "position", b"position", "user", b"user"]) -> builtins.bool: ...
|
||||||
def ClearField(self, field_name: typing.Literal["_hops_away", b"_hops_away", "channel", b"channel", "device_metrics", b"device_metrics", "hops_away", b"hops_away", "is_favorite", b"is_favorite", "last_heard", b"last_heard", "num", b"num", "position", b"position", "snr", b"snr", "user", b"user", "via_mqtt", b"via_mqtt"]) -> None: ...
|
def ClearField(self, field_name: typing.Literal["_hops_away", b"_hops_away", "bitfield", b"bitfield", "channel", b"channel", "device_metrics", b"device_metrics", "hops_away", b"hops_away", "is_favorite", b"is_favorite", "is_ignored", b"is_ignored", "last_heard", b"last_heard", "next_hop", b"next_hop", "num", b"num", "position", b"position", "snr", b"snr", "user", b"user", "via_mqtt", b"via_mqtt"]) -> None: ...
|
||||||
def WhichOneof(self, oneof_group: typing.Literal["_hops_away", b"_hops_away"]) -> typing.Literal["hops_away"] | None: ...
|
def WhichOneof(self, oneof_group: typing.Literal["_hops_away", b"_hops_away"]) -> typing.Literal["hops_away"] | None: ...
|
||||||
|
|
||||||
global___NodeInfoLite = NodeInfoLite
|
global___NodeInfoLite = NodeInfoLite
|
||||||
@@ -278,7 +261,6 @@ class DeviceState(google.protobuf.message.Message):
|
|||||||
DID_GPS_RESET_FIELD_NUMBER: builtins.int
|
DID_GPS_RESET_FIELD_NUMBER: builtins.int
|
||||||
RX_WAYPOINT_FIELD_NUMBER: builtins.int
|
RX_WAYPOINT_FIELD_NUMBER: builtins.int
|
||||||
NODE_REMOTE_HARDWARE_PINS_FIELD_NUMBER: builtins.int
|
NODE_REMOTE_HARDWARE_PINS_FIELD_NUMBER: builtins.int
|
||||||
NODE_DB_LITE_FIELD_NUMBER: builtins.int
|
|
||||||
version: builtins.int
|
version: builtins.int
|
||||||
"""
|
"""
|
||||||
A version integer used to invalidate old save files when we make
|
A version integer used to invalidate old save files when we make
|
||||||
@@ -293,7 +275,8 @@ class DeviceState(google.protobuf.message.Message):
|
|||||||
"""
|
"""
|
||||||
did_gps_reset: builtins.bool
|
did_gps_reset: builtins.bool
|
||||||
"""
|
"""
|
||||||
Some GPS receivers seem to have bogus settings from the factory, so we always do one factory reset.
|
Previously used to manage GPS factory resets.
|
||||||
|
Deprecated in 2.5.23
|
||||||
"""
|
"""
|
||||||
@property
|
@property
|
||||||
def my_node(self) -> meshtastic.protobuf.mesh_pb2.MyNodeInfo:
|
def my_node(self) -> meshtastic.protobuf.mesh_pb2.MyNodeInfo:
|
||||||
@@ -335,12 +318,6 @@ class DeviceState(google.protobuf.message.Message):
|
|||||||
The mesh's nodes with their available gpio pins for RemoteHardware module
|
The mesh's nodes with their available gpio pins for RemoteHardware module
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@property
|
|
||||||
def node_db_lite(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___NodeInfoLite]:
|
|
||||||
"""
|
|
||||||
New lite version of NodeDB to decrease memory footprint
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
@@ -353,13 +330,40 @@ class DeviceState(google.protobuf.message.Message):
|
|||||||
did_gps_reset: builtins.bool = ...,
|
did_gps_reset: builtins.bool = ...,
|
||||||
rx_waypoint: meshtastic.protobuf.mesh_pb2.MeshPacket | None = ...,
|
rx_waypoint: meshtastic.protobuf.mesh_pb2.MeshPacket | None = ...,
|
||||||
node_remote_hardware_pins: collections.abc.Iterable[meshtastic.protobuf.mesh_pb2.NodeRemoteHardwarePin] | None = ...,
|
node_remote_hardware_pins: collections.abc.Iterable[meshtastic.protobuf.mesh_pb2.NodeRemoteHardwarePin] | None = ...,
|
||||||
node_db_lite: collections.abc.Iterable[global___NodeInfoLite] | None = ...,
|
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
def HasField(self, field_name: typing.Literal["my_node", b"my_node", "owner", b"owner", "rx_text_message", b"rx_text_message", "rx_waypoint", b"rx_waypoint"]) -> builtins.bool: ...
|
def HasField(self, field_name: typing.Literal["my_node", b"my_node", "owner", b"owner", "rx_text_message", b"rx_text_message", "rx_waypoint", b"rx_waypoint"]) -> builtins.bool: ...
|
||||||
def ClearField(self, field_name: typing.Literal["did_gps_reset", b"did_gps_reset", "my_node", b"my_node", "no_save", b"no_save", "node_db_lite", b"node_db_lite", "node_remote_hardware_pins", b"node_remote_hardware_pins", "owner", b"owner", "receive_queue", b"receive_queue", "rx_text_message", b"rx_text_message", "rx_waypoint", b"rx_waypoint", "version", b"version"]) -> None: ...
|
def ClearField(self, field_name: typing.Literal["did_gps_reset", b"did_gps_reset", "my_node", b"my_node", "no_save", b"no_save", "node_remote_hardware_pins", b"node_remote_hardware_pins", "owner", b"owner", "receive_queue", b"receive_queue", "rx_text_message", b"rx_text_message", "rx_waypoint", b"rx_waypoint", "version", b"version"]) -> None: ...
|
||||||
|
|
||||||
global___DeviceState = DeviceState
|
global___DeviceState = DeviceState
|
||||||
|
|
||||||
|
@typing.final
|
||||||
|
class NodeDatabase(google.protobuf.message.Message):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||||
|
|
||||||
|
VERSION_FIELD_NUMBER: builtins.int
|
||||||
|
NODES_FIELD_NUMBER: builtins.int
|
||||||
|
version: builtins.int
|
||||||
|
"""
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
@property
|
||||||
|
def nodes(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___NodeInfoLite]:
|
||||||
|
"""
|
||||||
|
New lite version of NodeDB to decrease memory footprint
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
version: builtins.int = ...,
|
||||||
|
nodes: collections.abc.Iterable[global___NodeInfoLite] | None = ...,
|
||||||
|
) -> None: ...
|
||||||
|
def ClearField(self, field_name: typing.Literal["nodes", b"nodes", "version", b"version"]) -> None: ...
|
||||||
|
|
||||||
|
global___NodeDatabase = NodeDatabase
|
||||||
|
|
||||||
@typing.final
|
@typing.final
|
||||||
class ChannelFile(google.protobuf.message.Message):
|
class ChannelFile(google.protobuf.message.Message):
|
||||||
"""
|
"""
|
||||||
@@ -393,71 +397,62 @@ class ChannelFile(google.protobuf.message.Message):
|
|||||||
global___ChannelFile = ChannelFile
|
global___ChannelFile = ChannelFile
|
||||||
|
|
||||||
@typing.final
|
@typing.final
|
||||||
class OEMStore(google.protobuf.message.Message):
|
class BackupPreferences(google.protobuf.message.Message):
|
||||||
"""
|
"""
|
||||||
This can be used for customizing the firmware distribution. If populated,
|
The on-disk backup of the node's preferences
|
||||||
show a secondary bootup screen with custom logo and text for 2.5 seconds.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||||
|
|
||||||
OEM_ICON_WIDTH_FIELD_NUMBER: builtins.int
|
VERSION_FIELD_NUMBER: builtins.int
|
||||||
OEM_ICON_HEIGHT_FIELD_NUMBER: builtins.int
|
TIMESTAMP_FIELD_NUMBER: builtins.int
|
||||||
OEM_ICON_BITS_FIELD_NUMBER: builtins.int
|
CONFIG_FIELD_NUMBER: builtins.int
|
||||||
OEM_FONT_FIELD_NUMBER: builtins.int
|
MODULE_CONFIG_FIELD_NUMBER: builtins.int
|
||||||
OEM_TEXT_FIELD_NUMBER: builtins.int
|
CHANNELS_FIELD_NUMBER: builtins.int
|
||||||
OEM_AES_KEY_FIELD_NUMBER: builtins.int
|
OWNER_FIELD_NUMBER: builtins.int
|
||||||
OEM_LOCAL_CONFIG_FIELD_NUMBER: builtins.int
|
version: builtins.int
|
||||||
OEM_LOCAL_MODULE_CONFIG_FIELD_NUMBER: builtins.int
|
|
||||||
oem_icon_width: builtins.int
|
|
||||||
"""
|
"""
|
||||||
The Logo width in Px
|
The version of the backup
|
||||||
"""
|
"""
|
||||||
oem_icon_height: builtins.int
|
timestamp: builtins.int
|
||||||
"""
|
"""
|
||||||
The Logo height in Px
|
The timestamp of the backup (if node has time)
|
||||||
"""
|
|
||||||
oem_icon_bits: builtins.bytes
|
|
||||||
"""
|
|
||||||
The Logo in XBM bytechar format
|
|
||||||
"""
|
|
||||||
oem_font: global___ScreenFonts.ValueType
|
|
||||||
"""
|
|
||||||
Use this font for the OEM text.
|
|
||||||
"""
|
|
||||||
oem_text: builtins.str
|
|
||||||
"""
|
|
||||||
Use this font for the OEM text.
|
|
||||||
"""
|
|
||||||
oem_aes_key: builtins.bytes
|
|
||||||
"""
|
|
||||||
The default device encryption key, 16 or 32 byte
|
|
||||||
"""
|
"""
|
||||||
@property
|
@property
|
||||||
def oem_local_config(self) -> meshtastic.protobuf.localonly_pb2.LocalConfig:
|
def config(self) -> meshtastic.protobuf.localonly_pb2.LocalConfig:
|
||||||
"""
|
"""
|
||||||
A Preset LocalConfig to apply during factory reset
|
The node's configuration
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def oem_local_module_config(self) -> meshtastic.protobuf.localonly_pb2.LocalModuleConfig:
|
def module_config(self) -> meshtastic.protobuf.localonly_pb2.LocalModuleConfig:
|
||||||
"""
|
"""
|
||||||
A Preset LocalModuleConfig to apply during factory reset
|
The node's module configuration
|
||||||
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def channels(self) -> global___ChannelFile:
|
||||||
|
"""
|
||||||
|
The node's channels
|
||||||
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def owner(self) -> meshtastic.protobuf.mesh_pb2.User:
|
||||||
|
"""
|
||||||
|
The node's user (owner) information
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
oem_icon_width: builtins.int = ...,
|
version: builtins.int = ...,
|
||||||
oem_icon_height: builtins.int = ...,
|
timestamp: builtins.int = ...,
|
||||||
oem_icon_bits: builtins.bytes = ...,
|
config: meshtastic.protobuf.localonly_pb2.LocalConfig | None = ...,
|
||||||
oem_font: global___ScreenFonts.ValueType = ...,
|
module_config: meshtastic.protobuf.localonly_pb2.LocalModuleConfig | None = ...,
|
||||||
oem_text: builtins.str = ...,
|
channels: global___ChannelFile | None = ...,
|
||||||
oem_aes_key: builtins.bytes = ...,
|
owner: meshtastic.protobuf.mesh_pb2.User | None = ...,
|
||||||
oem_local_config: meshtastic.protobuf.localonly_pb2.LocalConfig | None = ...,
|
|
||||||
oem_local_module_config: meshtastic.protobuf.localonly_pb2.LocalModuleConfig | None = ...,
|
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
def HasField(self, field_name: typing.Literal["oem_local_config", b"oem_local_config", "oem_local_module_config", b"oem_local_module_config"]) -> builtins.bool: ...
|
def HasField(self, field_name: typing.Literal["channels", b"channels", "config", b"config", "module_config", b"module_config", "owner", b"owner"]) -> builtins.bool: ...
|
||||||
def ClearField(self, field_name: typing.Literal["oem_aes_key", b"oem_aes_key", "oem_font", b"oem_font", "oem_icon_bits", b"oem_icon_bits", "oem_icon_height", b"oem_icon_height", "oem_icon_width", b"oem_icon_width", "oem_local_config", b"oem_local_config", "oem_local_module_config", b"oem_local_module_config", "oem_text", b"oem_text"]) -> None: ...
|
def ClearField(self, field_name: typing.Literal["channels", b"channels", "config", b"config", "module_config", b"module_config", "owner", b"owner", "timestamp", b"timestamp", "version", b"version"]) -> None: ...
|
||||||
|
|
||||||
global___OEMStore = OEMStore
|
global___BackupPreferences = BackupPreferences
|
||||||
|
|||||||
30
meshtastic/protobuf/interdevice_pb2.py
generated
Normal file
30
meshtastic/protobuf/interdevice_pb2.py
generated
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
# source: meshtastic/protobuf/interdevice.proto
|
||||||
|
"""Generated protocol buffer code."""
|
||||||
|
from google.protobuf import descriptor as _descriptor
|
||||||
|
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||||
|
from google.protobuf import symbol_database as _symbol_database
|
||||||
|
from google.protobuf.internal import builder as _builder
|
||||||
|
# @@protoc_insertion_point(imports)
|
||||||
|
|
||||||
|
_sym_db = _symbol_database.Default()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n%meshtastic/protobuf/interdevice.proto\x12\x13meshtastic.protobuf\"s\n\nSensorData\x12.\n\x04type\x18\x01 \x01(\x0e\x32 .meshtastic.protobuf.MessageType\x12\x15\n\x0b\x66loat_value\x18\x02 \x01(\x02H\x00\x12\x16\n\x0cuint32_value\x18\x03 \x01(\rH\x00\x42\x06\n\x04\x64\x61ta\"_\n\x12InterdeviceMessage\x12\x0e\n\x04nmea\x18\x01 \x01(\tH\x00\x12\x31\n\x06sensor\x18\x02 \x01(\x0b\x32\x1f.meshtastic.protobuf.SensorDataH\x00\x42\x06\n\x04\x64\x61ta*\xd5\x01\n\x0bMessageType\x12\x07\n\x03\x41\x43K\x10\x00\x12\x15\n\x10\x43OLLECT_INTERVAL\x10\xa0\x01\x12\x0c\n\x07\x42\x45\x45P_ON\x10\xa1\x01\x12\r\n\x08\x42\x45\x45P_OFF\x10\xa2\x01\x12\r\n\x08SHUTDOWN\x10\xa3\x01\x12\r\n\x08POWER_ON\x10\xa4\x01\x12\x0f\n\nSCD41_TEMP\x10\xb0\x01\x12\x13\n\x0eSCD41_HUMIDITY\x10\xb1\x01\x12\x0e\n\tSCD41_CO2\x10\xb2\x01\x12\x0f\n\nAHT20_TEMP\x10\xb3\x01\x12\x13\n\x0e\x41HT20_HUMIDITY\x10\xb4\x01\x12\x0f\n\nTVOC_INDEX\x10\xb5\x01\x42\x66\n\x13\x63om.geeksville.meshB\x11InterdeviceProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||||
|
|
||||||
|
_globals = globals()
|
||||||
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||||
|
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.interdevice_pb2', _globals)
|
||||||
|
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||||
|
DESCRIPTOR._options = None
|
||||||
|
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\021InterdeviceProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
|
||||||
|
_globals['_MESSAGETYPE']._serialized_start=277
|
||||||
|
_globals['_MESSAGETYPE']._serialized_end=490
|
||||||
|
_globals['_SENSORDATA']._serialized_start=62
|
||||||
|
_globals['_SENSORDATA']._serialized_end=177
|
||||||
|
_globals['_INTERDEVICEMESSAGE']._serialized_start=179
|
||||||
|
_globals['_INTERDEVICEMESSAGE']._serialized_end=274
|
||||||
|
# @@protoc_insertion_point(module_scope)
|
||||||
105
meshtastic/protobuf/interdevice_pb2.pyi
generated
Normal file
105
meshtastic/protobuf/interdevice_pb2.pyi
generated
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
"""
|
||||||
|
@generated by mypy-protobuf. Do not edit manually!
|
||||||
|
isort:skip_file
|
||||||
|
"""
|
||||||
|
|
||||||
|
import builtins
|
||||||
|
import google.protobuf.descriptor
|
||||||
|
import google.protobuf.internal.enum_type_wrapper
|
||||||
|
import google.protobuf.message
|
||||||
|
import sys
|
||||||
|
import typing
|
||||||
|
|
||||||
|
if sys.version_info >= (3, 10):
|
||||||
|
import typing as typing_extensions
|
||||||
|
else:
|
||||||
|
import typing_extensions
|
||||||
|
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
|
||||||
|
|
||||||
|
class _MessageType:
|
||||||
|
ValueType = typing.NewType("ValueType", builtins.int)
|
||||||
|
V: typing_extensions.TypeAlias = ValueType
|
||||||
|
|
||||||
|
class _MessageTypeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_MessageType.ValueType], builtins.type):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
|
||||||
|
ACK: _MessageType.ValueType # 0
|
||||||
|
COLLECT_INTERVAL: _MessageType.ValueType # 160
|
||||||
|
"""in ms"""
|
||||||
|
BEEP_ON: _MessageType.ValueType # 161
|
||||||
|
"""duration ms"""
|
||||||
|
BEEP_OFF: _MessageType.ValueType # 162
|
||||||
|
"""cancel prematurely"""
|
||||||
|
SHUTDOWN: _MessageType.ValueType # 163
|
||||||
|
POWER_ON: _MessageType.ValueType # 164
|
||||||
|
SCD41_TEMP: _MessageType.ValueType # 176
|
||||||
|
SCD41_HUMIDITY: _MessageType.ValueType # 177
|
||||||
|
SCD41_CO2: _MessageType.ValueType # 178
|
||||||
|
AHT20_TEMP: _MessageType.ValueType # 179
|
||||||
|
AHT20_HUMIDITY: _MessageType.ValueType # 180
|
||||||
|
TVOC_INDEX: _MessageType.ValueType # 181
|
||||||
|
|
||||||
|
class MessageType(_MessageType, metaclass=_MessageTypeEnumTypeWrapper):
|
||||||
|
"""encapsulate up to 1k of NMEA string data"""
|
||||||
|
|
||||||
|
ACK: MessageType.ValueType # 0
|
||||||
|
COLLECT_INTERVAL: MessageType.ValueType # 160
|
||||||
|
"""in ms"""
|
||||||
|
BEEP_ON: MessageType.ValueType # 161
|
||||||
|
"""duration ms"""
|
||||||
|
BEEP_OFF: MessageType.ValueType # 162
|
||||||
|
"""cancel prematurely"""
|
||||||
|
SHUTDOWN: MessageType.ValueType # 163
|
||||||
|
POWER_ON: MessageType.ValueType # 164
|
||||||
|
SCD41_TEMP: MessageType.ValueType # 176
|
||||||
|
SCD41_HUMIDITY: MessageType.ValueType # 177
|
||||||
|
SCD41_CO2: MessageType.ValueType # 178
|
||||||
|
AHT20_TEMP: MessageType.ValueType # 179
|
||||||
|
AHT20_HUMIDITY: MessageType.ValueType # 180
|
||||||
|
TVOC_INDEX: MessageType.ValueType # 181
|
||||||
|
global___MessageType = MessageType
|
||||||
|
|
||||||
|
@typing.final
|
||||||
|
class SensorData(google.protobuf.message.Message):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||||
|
|
||||||
|
TYPE_FIELD_NUMBER: builtins.int
|
||||||
|
FLOAT_VALUE_FIELD_NUMBER: builtins.int
|
||||||
|
UINT32_VALUE_FIELD_NUMBER: builtins.int
|
||||||
|
type: global___MessageType.ValueType
|
||||||
|
"""The message type"""
|
||||||
|
float_value: builtins.float
|
||||||
|
uint32_value: builtins.int
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
type: global___MessageType.ValueType = ...,
|
||||||
|
float_value: builtins.float = ...,
|
||||||
|
uint32_value: builtins.int = ...,
|
||||||
|
) -> None: ...
|
||||||
|
def HasField(self, field_name: typing.Literal["data", b"data", "float_value", b"float_value", "uint32_value", b"uint32_value"]) -> builtins.bool: ...
|
||||||
|
def ClearField(self, field_name: typing.Literal["data", b"data", "float_value", b"float_value", "type", b"type", "uint32_value", b"uint32_value"]) -> None: ...
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["data", b"data"]) -> typing.Literal["float_value", "uint32_value"] | None: ...
|
||||||
|
|
||||||
|
global___SensorData = SensorData
|
||||||
|
|
||||||
|
@typing.final
|
||||||
|
class InterdeviceMessage(google.protobuf.message.Message):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||||
|
|
||||||
|
NMEA_FIELD_NUMBER: builtins.int
|
||||||
|
SENSOR_FIELD_NUMBER: builtins.int
|
||||||
|
nmea: builtins.str
|
||||||
|
@property
|
||||||
|
def sensor(self) -> global___SensorData: ...
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
nmea: builtins.str = ...,
|
||||||
|
sensor: global___SensorData | None = ...,
|
||||||
|
) -> None: ...
|
||||||
|
def HasField(self, field_name: typing.Literal["data", b"data", "nmea", b"nmea", "sensor", b"sensor"]) -> builtins.bool: ...
|
||||||
|
def ClearField(self, field_name: typing.Literal["data", b"data", "nmea", b"nmea", "sensor", b"sensor"]) -> None: ...
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["data", b"data"]) -> typing.Literal["nmea", "sensor"] | None: ...
|
||||||
|
|
||||||
|
global___InterdeviceMessage = InterdeviceMessage
|
||||||
157
meshtastic/protobuf/mesh_pb2.py
generated
157
meshtastic/protobuf/mesh_pb2.py
generated
File diff suppressed because one or more lines are too long
803
meshtastic/protobuf/mesh_pb2.pyi
generated
803
meshtastic/protobuf/mesh_pb2.pyi
generated
File diff suppressed because it is too large
Load Diff
86
meshtastic/protobuf/module_config_pb2.py
generated
86
meshtastic/protobuf/module_config_pb2.py
generated
File diff suppressed because one or more lines are too long
74
meshtastic/protobuf/module_config_pb2.pyi
generated
74
meshtastic/protobuf/module_config_pb2.pyi
generated
@@ -165,6 +165,7 @@ class ModuleConfig(google.protobuf.message.Message):
|
|||||||
|
|
||||||
PUBLISH_INTERVAL_SECS_FIELD_NUMBER: builtins.int
|
PUBLISH_INTERVAL_SECS_FIELD_NUMBER: builtins.int
|
||||||
POSITION_PRECISION_FIELD_NUMBER: builtins.int
|
POSITION_PRECISION_FIELD_NUMBER: builtins.int
|
||||||
|
SHOULD_REPORT_LOCATION_FIELD_NUMBER: builtins.int
|
||||||
publish_interval_secs: builtins.int
|
publish_interval_secs: builtins.int
|
||||||
"""
|
"""
|
||||||
How often we should report our info to the map (in seconds)
|
How often we should report our info to the map (in seconds)
|
||||||
@@ -173,13 +174,18 @@ class ModuleConfig(google.protobuf.message.Message):
|
|||||||
"""
|
"""
|
||||||
Bits of precision for the location sent (default of 32 is full precision).
|
Bits of precision for the location sent (default of 32 is full precision).
|
||||||
"""
|
"""
|
||||||
|
should_report_location: builtins.bool
|
||||||
|
"""
|
||||||
|
Whether we have opted-in to report our location to the map
|
||||||
|
"""
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
publish_interval_secs: builtins.int = ...,
|
publish_interval_secs: builtins.int = ...,
|
||||||
position_precision: builtins.int = ...,
|
position_precision: builtins.int = ...,
|
||||||
|
should_report_location: builtins.bool = ...,
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
def ClearField(self, field_name: typing.Literal["position_precision", b"position_precision", "publish_interval_secs", b"publish_interval_secs"]) -> None: ...
|
def ClearField(self, field_name: typing.Literal["position_precision", b"position_precision", "publish_interval_secs", b"publish_interval_secs", "should_report_location", b"should_report_location"]) -> None: ...
|
||||||
|
|
||||||
@typing.final
|
@typing.final
|
||||||
class RemoteHardwareConfig(google.protobuf.message.Message):
|
class RemoteHardwareConfig(google.protobuf.message.Message):
|
||||||
@@ -225,6 +231,7 @@ class ModuleConfig(google.protobuf.message.Message):
|
|||||||
|
|
||||||
ENABLED_FIELD_NUMBER: builtins.int
|
ENABLED_FIELD_NUMBER: builtins.int
|
||||||
UPDATE_INTERVAL_FIELD_NUMBER: builtins.int
|
UPDATE_INTERVAL_FIELD_NUMBER: builtins.int
|
||||||
|
TRANSMIT_OVER_LORA_FIELD_NUMBER: builtins.int
|
||||||
enabled: builtins.bool
|
enabled: builtins.bool
|
||||||
"""
|
"""
|
||||||
Whether the Module is enabled
|
Whether the Module is enabled
|
||||||
@@ -232,15 +239,21 @@ class ModuleConfig(google.protobuf.message.Message):
|
|||||||
update_interval: builtins.int
|
update_interval: builtins.int
|
||||||
"""
|
"""
|
||||||
Interval in seconds of how often we should try to send our
|
Interval in seconds of how often we should try to send our
|
||||||
Neighbor Info to the mesh
|
Neighbor Info (minimum is 14400, i.e., 4 hours)
|
||||||
|
"""
|
||||||
|
transmit_over_lora: builtins.bool
|
||||||
|
"""
|
||||||
|
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.
|
||||||
"""
|
"""
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
enabled: builtins.bool = ...,
|
enabled: builtins.bool = ...,
|
||||||
update_interval: builtins.int = ...,
|
update_interval: builtins.int = ...,
|
||||||
|
transmit_over_lora: builtins.bool = ...,
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
def ClearField(self, field_name: typing.Literal["enabled", b"enabled", "update_interval", b"update_interval"]) -> None: ...
|
def ClearField(self, field_name: typing.Literal["enabled", b"enabled", "transmit_over_lora", b"transmit_over_lora", "update_interval", b"update_interval"]) -> None: ...
|
||||||
|
|
||||||
@typing.final
|
@typing.final
|
||||||
class DetectionSensorConfig(google.protobuf.message.Message):
|
class DetectionSensorConfig(google.protobuf.message.Message):
|
||||||
@@ -547,6 +560,14 @@ class ModuleConfig(google.protobuf.message.Message):
|
|||||||
"""NMEA messages specifically tailored for CalTopo"""
|
"""NMEA messages specifically tailored for CalTopo"""
|
||||||
WS85: ModuleConfig.SerialConfig._Serial_Mode.ValueType # 6
|
WS85: ModuleConfig.SerialConfig._Serial_Mode.ValueType # 6
|
||||||
"""Ecowitt WS85 weather station"""
|
"""Ecowitt WS85 weather station"""
|
||||||
|
VE_DIRECT: ModuleConfig.SerialConfig._Serial_Mode.ValueType # 7
|
||||||
|
"""VE.Direct is a serial protocol used by Victron Energy products
|
||||||
|
https://beta.ivc.no/wiki/index.php/Victron_VE_Direct_DIY_Cable
|
||||||
|
"""
|
||||||
|
MS_CONFIG: ModuleConfig.SerialConfig._Serial_Mode.ValueType # 8
|
||||||
|
"""Used to configure and view some parameters of MeshSolar.
|
||||||
|
https://heltec.org/project/meshsolar/
|
||||||
|
"""
|
||||||
|
|
||||||
class Serial_Mode(_Serial_Mode, metaclass=_Serial_ModeEnumTypeWrapper):
|
class Serial_Mode(_Serial_Mode, metaclass=_Serial_ModeEnumTypeWrapper):
|
||||||
"""
|
"""
|
||||||
@@ -562,6 +583,14 @@ class ModuleConfig(google.protobuf.message.Message):
|
|||||||
"""NMEA messages specifically tailored for CalTopo"""
|
"""NMEA messages specifically tailored for CalTopo"""
|
||||||
WS85: ModuleConfig.SerialConfig.Serial_Mode.ValueType # 6
|
WS85: ModuleConfig.SerialConfig.Serial_Mode.ValueType # 6
|
||||||
"""Ecowitt WS85 weather station"""
|
"""Ecowitt WS85 weather station"""
|
||||||
|
VE_DIRECT: ModuleConfig.SerialConfig.Serial_Mode.ValueType # 7
|
||||||
|
"""VE.Direct is a serial protocol used by Victron Energy products
|
||||||
|
https://beta.ivc.no/wiki/index.php/Victron_VE_Direct_DIY_Cable
|
||||||
|
"""
|
||||||
|
MS_CONFIG: ModuleConfig.SerialConfig.Serial_Mode.ValueType # 8
|
||||||
|
"""Used to configure and view some parameters of MeshSolar.
|
||||||
|
https://heltec.org/project/meshsolar/
|
||||||
|
"""
|
||||||
|
|
||||||
ENABLED_FIELD_NUMBER: builtins.int
|
ENABLED_FIELD_NUMBER: builtins.int
|
||||||
ECHO_FIELD_NUMBER: builtins.int
|
ECHO_FIELD_NUMBER: builtins.int
|
||||||
@@ -795,6 +824,7 @@ class ModuleConfig(google.protobuf.message.Message):
|
|||||||
ENABLED_FIELD_NUMBER: builtins.int
|
ENABLED_FIELD_NUMBER: builtins.int
|
||||||
SENDER_FIELD_NUMBER: builtins.int
|
SENDER_FIELD_NUMBER: builtins.int
|
||||||
SAVE_FIELD_NUMBER: builtins.int
|
SAVE_FIELD_NUMBER: builtins.int
|
||||||
|
CLEAR_ON_REBOOT_FIELD_NUMBER: builtins.int
|
||||||
enabled: builtins.bool
|
enabled: builtins.bool
|
||||||
"""
|
"""
|
||||||
Enable the Range Test Module
|
Enable the Range Test Module
|
||||||
@@ -808,14 +838,20 @@ class ModuleConfig(google.protobuf.message.Message):
|
|||||||
Bool value indicating that this node should save a RangeTest.csv file.
|
Bool value indicating that this node should save a RangeTest.csv file.
|
||||||
ESP32 Only
|
ESP32 Only
|
||||||
"""
|
"""
|
||||||
|
clear_on_reboot: builtins.bool
|
||||||
|
"""
|
||||||
|
Bool indicating that the node should cleanup / destroy it's RangeTest.csv file.
|
||||||
|
ESP32 Only
|
||||||
|
"""
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
enabled: builtins.bool = ...,
|
enabled: builtins.bool = ...,
|
||||||
sender: builtins.int = ...,
|
sender: builtins.int = ...,
|
||||||
save: builtins.bool = ...,
|
save: builtins.bool = ...,
|
||||||
|
clear_on_reboot: builtins.bool = ...,
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
def ClearField(self, field_name: typing.Literal["enabled", b"enabled", "save", b"save", "sender", b"sender"]) -> None: ...
|
def ClearField(self, field_name: typing.Literal["clear_on_reboot", b"clear_on_reboot", "enabled", b"enabled", "save", b"save", "sender", b"sender"]) -> None: ...
|
||||||
|
|
||||||
@typing.final
|
@typing.final
|
||||||
class TelemetryConfig(google.protobuf.message.Message):
|
class TelemetryConfig(google.protobuf.message.Message):
|
||||||
@@ -835,6 +871,9 @@ class ModuleConfig(google.protobuf.message.Message):
|
|||||||
POWER_MEASUREMENT_ENABLED_FIELD_NUMBER: builtins.int
|
POWER_MEASUREMENT_ENABLED_FIELD_NUMBER: builtins.int
|
||||||
POWER_UPDATE_INTERVAL_FIELD_NUMBER: builtins.int
|
POWER_UPDATE_INTERVAL_FIELD_NUMBER: builtins.int
|
||||||
POWER_SCREEN_ENABLED_FIELD_NUMBER: builtins.int
|
POWER_SCREEN_ENABLED_FIELD_NUMBER: builtins.int
|
||||||
|
HEALTH_MEASUREMENT_ENABLED_FIELD_NUMBER: builtins.int
|
||||||
|
HEALTH_UPDATE_INTERVAL_FIELD_NUMBER: builtins.int
|
||||||
|
HEALTH_SCREEN_ENABLED_FIELD_NUMBER: builtins.int
|
||||||
device_update_interval: builtins.int
|
device_update_interval: builtins.int
|
||||||
"""
|
"""
|
||||||
Interval in seconds of how often we should try to send our
|
Interval in seconds of how often we should try to send our
|
||||||
@@ -870,18 +909,30 @@ class ModuleConfig(google.protobuf.message.Message):
|
|||||||
"""
|
"""
|
||||||
power_measurement_enabled: builtins.bool
|
power_measurement_enabled: builtins.bool
|
||||||
"""
|
"""
|
||||||
Interval in seconds of how often we should try to send our
|
Enable/disable Power metrics
|
||||||
air quality metrics to the mesh
|
|
||||||
"""
|
"""
|
||||||
power_update_interval: builtins.int
|
power_update_interval: builtins.int
|
||||||
"""
|
"""
|
||||||
Interval in seconds of how often we should try to send our
|
Interval in seconds of how often we should try to send our
|
||||||
air quality metrics to the mesh
|
power metrics to the mesh
|
||||||
"""
|
"""
|
||||||
power_screen_enabled: builtins.bool
|
power_screen_enabled: builtins.bool
|
||||||
"""
|
"""
|
||||||
|
Enable/Disable the power measurement module on-device display
|
||||||
|
"""
|
||||||
|
health_measurement_enabled: builtins.bool
|
||||||
|
"""
|
||||||
|
Preferences for the (Health) Telemetry Module
|
||||||
|
Enable/Disable the telemetry measurement module measurement collection
|
||||||
|
"""
|
||||||
|
health_update_interval: builtins.int
|
||||||
|
"""
|
||||||
Interval in seconds of how often we should try to send our
|
Interval in seconds of how often we should try to send our
|
||||||
air quality metrics to the mesh
|
health metrics to the mesh
|
||||||
|
"""
|
||||||
|
health_screen_enabled: builtins.bool
|
||||||
|
"""
|
||||||
|
Enable/Disable the health telemetry module on-device display
|
||||||
"""
|
"""
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -896,13 +947,16 @@ class ModuleConfig(google.protobuf.message.Message):
|
|||||||
power_measurement_enabled: builtins.bool = ...,
|
power_measurement_enabled: builtins.bool = ...,
|
||||||
power_update_interval: builtins.int = ...,
|
power_update_interval: builtins.int = ...,
|
||||||
power_screen_enabled: builtins.bool = ...,
|
power_screen_enabled: builtins.bool = ...,
|
||||||
|
health_measurement_enabled: builtins.bool = ...,
|
||||||
|
health_update_interval: builtins.int = ...,
|
||||||
|
health_screen_enabled: builtins.bool = ...,
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
def ClearField(self, field_name: typing.Literal["air_quality_enabled", b"air_quality_enabled", "air_quality_interval", b"air_quality_interval", "device_update_interval", b"device_update_interval", "environment_display_fahrenheit", b"environment_display_fahrenheit", "environment_measurement_enabled", b"environment_measurement_enabled", "environment_screen_enabled", b"environment_screen_enabled", "environment_update_interval", b"environment_update_interval", "power_measurement_enabled", b"power_measurement_enabled", "power_screen_enabled", b"power_screen_enabled", "power_update_interval", b"power_update_interval"]) -> None: ...
|
def ClearField(self, field_name: typing.Literal["air_quality_enabled", b"air_quality_enabled", "air_quality_interval", b"air_quality_interval", "device_update_interval", b"device_update_interval", "environment_display_fahrenheit", b"environment_display_fahrenheit", "environment_measurement_enabled", b"environment_measurement_enabled", "environment_screen_enabled", b"environment_screen_enabled", "environment_update_interval", b"environment_update_interval", "health_measurement_enabled", b"health_measurement_enabled", "health_screen_enabled", b"health_screen_enabled", "health_update_interval", b"health_update_interval", "power_measurement_enabled", b"power_measurement_enabled", "power_screen_enabled", b"power_screen_enabled", "power_update_interval", b"power_update_interval"]) -> None: ...
|
||||||
|
|
||||||
@typing.final
|
@typing.final
|
||||||
class CannedMessageConfig(google.protobuf.message.Message):
|
class CannedMessageConfig(google.protobuf.message.Message):
|
||||||
"""
|
"""
|
||||||
TODO: REPLACE
|
Canned Messages Module Config
|
||||||
"""
|
"""
|
||||||
|
|
||||||
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||||
|
|||||||
4
meshtastic/protobuf/mqtt_pb2.py
generated
4
meshtastic/protobuf/mqtt_pb2.py
generated
@@ -15,7 +15,7 @@ from meshtastic.protobuf import config_pb2 as meshtastic_dot_protobuf_dot_config
|
|||||||
from meshtastic.protobuf import mesh_pb2 as meshtastic_dot_protobuf_dot_mesh__pb2
|
from meshtastic.protobuf import mesh_pb2 as meshtastic_dot_protobuf_dot_mesh__pb2
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1emeshtastic/protobuf/mqtt.proto\x12\x13meshtastic.protobuf\x1a meshtastic/protobuf/config.proto\x1a\x1emeshtastic/protobuf/mesh.proto\"j\n\x0fServiceEnvelope\x12/\n\x06packet\x18\x01 \x01(\x0b\x32\x1f.meshtastic.protobuf.MeshPacket\x12\x12\n\nchannel_id\x18\x02 \x01(\t\x12\x12\n\ngateway_id\x18\x03 \x01(\t\"\xe0\x03\n\tMapReport\x12\x11\n\tlong_name\x18\x01 \x01(\t\x12\x12\n\nshort_name\x18\x02 \x01(\t\x12;\n\x04role\x18\x03 \x01(\x0e\x32-.meshtastic.protobuf.Config.DeviceConfig.Role\x12\x34\n\x08hw_model\x18\x04 \x01(\x0e\x32\".meshtastic.protobuf.HardwareModel\x12\x18\n\x10\x66irmware_version\x18\x05 \x01(\t\x12\x41\n\x06region\x18\x06 \x01(\x0e\x32\x31.meshtastic.protobuf.Config.LoRaConfig.RegionCode\x12H\n\x0cmodem_preset\x18\x07 \x01(\x0e\x32\x32.meshtastic.protobuf.Config.LoRaConfig.ModemPreset\x12\x1b\n\x13has_default_channel\x18\x08 \x01(\x08\x12\x12\n\nlatitude_i\x18\t \x01(\x0f\x12\x13\n\x0blongitude_i\x18\n \x01(\x0f\x12\x10\n\x08\x61ltitude\x18\x0b \x01(\x05\x12\x1a\n\x12position_precision\x18\x0c \x01(\r\x12\x1e\n\x16num_online_local_nodes\x18\r \x01(\rB_\n\x13\x63om.geeksville.meshB\nMQTTProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1emeshtastic/protobuf/mqtt.proto\x12\x13meshtastic.protobuf\x1a meshtastic/protobuf/config.proto\x1a\x1emeshtastic/protobuf/mesh.proto\"j\n\x0fServiceEnvelope\x12/\n\x06packet\x18\x01 \x01(\x0b\x32\x1f.meshtastic.protobuf.MeshPacket\x12\x12\n\nchannel_id\x18\x02 \x01(\t\x12\x12\n\ngateway_id\x18\x03 \x01(\t\"\x83\x04\n\tMapReport\x12\x11\n\tlong_name\x18\x01 \x01(\t\x12\x12\n\nshort_name\x18\x02 \x01(\t\x12;\n\x04role\x18\x03 \x01(\x0e\x32-.meshtastic.protobuf.Config.DeviceConfig.Role\x12\x34\n\x08hw_model\x18\x04 \x01(\x0e\x32\".meshtastic.protobuf.HardwareModel\x12\x18\n\x10\x66irmware_version\x18\x05 \x01(\t\x12\x41\n\x06region\x18\x06 \x01(\x0e\x32\x31.meshtastic.protobuf.Config.LoRaConfig.RegionCode\x12H\n\x0cmodem_preset\x18\x07 \x01(\x0e\x32\x32.meshtastic.protobuf.Config.LoRaConfig.ModemPreset\x12\x1b\n\x13has_default_channel\x18\x08 \x01(\x08\x12\x12\n\nlatitude_i\x18\t \x01(\x0f\x12\x13\n\x0blongitude_i\x18\n \x01(\x0f\x12\x10\n\x08\x61ltitude\x18\x0b \x01(\x05\x12\x1a\n\x12position_precision\x18\x0c \x01(\r\x12\x1e\n\x16num_online_local_nodes\x18\r \x01(\r\x12!\n\x19has_opted_report_location\x18\x0e \x01(\x08\x42_\n\x13\x63om.geeksville.meshB\nMQTTProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||||
|
|
||||||
_globals = globals()
|
_globals = globals()
|
||||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||||
@@ -26,5 +26,5 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|||||||
_globals['_SERVICEENVELOPE']._serialized_start=121
|
_globals['_SERVICEENVELOPE']._serialized_start=121
|
||||||
_globals['_SERVICEENVELOPE']._serialized_end=227
|
_globals['_SERVICEENVELOPE']._serialized_end=227
|
||||||
_globals['_MAPREPORT']._serialized_start=230
|
_globals['_MAPREPORT']._serialized_start=230
|
||||||
_globals['_MAPREPORT']._serialized_end=710
|
_globals['_MAPREPORT']._serialized_end=745
|
||||||
# @@protoc_insertion_point(module_scope)
|
# @@protoc_insertion_point(module_scope)
|
||||||
|
|||||||
9
meshtastic/protobuf/mqtt_pb2.pyi
generated
9
meshtastic/protobuf/mqtt_pb2.pyi
generated
@@ -72,6 +72,7 @@ class MapReport(google.protobuf.message.Message):
|
|||||||
ALTITUDE_FIELD_NUMBER: builtins.int
|
ALTITUDE_FIELD_NUMBER: builtins.int
|
||||||
POSITION_PRECISION_FIELD_NUMBER: builtins.int
|
POSITION_PRECISION_FIELD_NUMBER: builtins.int
|
||||||
NUM_ONLINE_LOCAL_NODES_FIELD_NUMBER: builtins.int
|
NUM_ONLINE_LOCAL_NODES_FIELD_NUMBER: builtins.int
|
||||||
|
HAS_OPTED_REPORT_LOCATION_FIELD_NUMBER: builtins.int
|
||||||
long_name: builtins.str
|
long_name: builtins.str
|
||||||
"""
|
"""
|
||||||
A full name for this user, i.e. "Kevin Hester"
|
A full name for this user, i.e. "Kevin Hester"
|
||||||
@@ -126,6 +127,11 @@ class MapReport(google.protobuf.message.Message):
|
|||||||
"""
|
"""
|
||||||
Number of online nodes (heard in the last 2 hours) this node has in its list that were received locally (not via MQTT)
|
Number of online nodes (heard in the last 2 hours) this node has in its list that were received locally (not via MQTT)
|
||||||
"""
|
"""
|
||||||
|
has_opted_report_location: builtins.bool
|
||||||
|
"""
|
||||||
|
User has opted in to share their location (map report) with the mqtt server
|
||||||
|
Controlled by map_report.should_report_location
|
||||||
|
"""
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
@@ -142,7 +148,8 @@ class MapReport(google.protobuf.message.Message):
|
|||||||
altitude: builtins.int = ...,
|
altitude: builtins.int = ...,
|
||||||
position_precision: builtins.int = ...,
|
position_precision: builtins.int = ...,
|
||||||
num_online_local_nodes: builtins.int = ...,
|
num_online_local_nodes: builtins.int = ...,
|
||||||
|
has_opted_report_location: builtins.bool = ...,
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
def ClearField(self, field_name: typing.Literal["altitude", b"altitude", "firmware_version", b"firmware_version", "has_default_channel", b"has_default_channel", "hw_model", b"hw_model", "latitude_i", b"latitude_i", "long_name", b"long_name", "longitude_i", b"longitude_i", "modem_preset", b"modem_preset", "num_online_local_nodes", b"num_online_local_nodes", "position_precision", b"position_precision", "region", b"region", "role", b"role", "short_name", b"short_name"]) -> None: ...
|
def ClearField(self, field_name: typing.Literal["altitude", b"altitude", "firmware_version", b"firmware_version", "has_default_channel", b"has_default_channel", "has_opted_report_location", b"has_opted_report_location", "hw_model", b"hw_model", "latitude_i", b"latitude_i", "long_name", b"long_name", "longitude_i", b"longitude_i", "modem_preset", b"modem_preset", "num_online_local_nodes", b"num_online_local_nodes", "position_precision", b"position_precision", "region", b"region", "role", b"role", "short_name", b"short_name"]) -> None: ...
|
||||||
|
|
||||||
global___MapReport = MapReport
|
global___MapReport = MapReport
|
||||||
|
|||||||
35
meshtastic/protobuf/nanopb_pb2.py
generated
Normal file
35
meshtastic/protobuf/nanopb_pb2.py
generated
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
# source: meshtastic/protobuf/nanopb.proto
|
||||||
|
"""Generated protocol buffer code."""
|
||||||
|
from google.protobuf import descriptor as _descriptor
|
||||||
|
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||||
|
from google.protobuf import symbol_database as _symbol_database
|
||||||
|
from google.protobuf.internal import builder as _builder
|
||||||
|
# @@protoc_insertion_point(imports)
|
||||||
|
|
||||||
|
_sym_db = _symbol_database.Default()
|
||||||
|
|
||||||
|
|
||||||
|
from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n meshtastic/protobuf/nanopb.proto\x1a google/protobuf/descriptor.proto\"\xa4\x07\n\rNanoPBOptions\x12\x10\n\x08max_size\x18\x01 \x01(\x05\x12\x12\n\nmax_length\x18\x0e \x01(\x05\x12\x11\n\tmax_count\x18\x02 \x01(\x05\x12&\n\x08int_size\x18\x07 \x01(\x0e\x32\x08.IntSize:\nIS_DEFAULT\x12$\n\x04type\x18\x03 \x01(\x0e\x32\n.FieldType:\nFT_DEFAULT\x12\x18\n\nlong_names\x18\x04 \x01(\x08:\x04true\x12\x1c\n\rpacked_struct\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1a\n\x0bpacked_enum\x18\n \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0cskip_message\x18\x06 \x01(\x08:\x05\x66\x61lse\x12\x18\n\tno_unions\x18\x08 \x01(\x08:\x05\x66\x61lse\x12\r\n\x05msgid\x18\t \x01(\r\x12\x1e\n\x0f\x61nonymous_oneof\x18\x0b \x01(\x08:\x05\x66\x61lse\x12\x15\n\x06proto3\x18\x0c \x01(\x08:\x05\x66\x61lse\x12#\n\x14proto3_singular_msgs\x18\x15 \x01(\x08:\x05\x66\x61lse\x12\x1d\n\x0e\x65num_to_string\x18\r \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0c\x66ixed_length\x18\x0f \x01(\x08:\x05\x66\x61lse\x12\x1a\n\x0b\x66ixed_count\x18\x10 \x01(\x08:\x05\x66\x61lse\x12\x1e\n\x0fsubmsg_callback\x18\x16 \x01(\x08:\x05\x66\x61lse\x12/\n\x0cmangle_names\x18\x11 \x01(\x0e\x32\x11.TypenameMangling:\x06M_NONE\x12(\n\x11\x63\x61llback_datatype\x18\x12 \x01(\t:\rpb_callback_t\x12\x34\n\x11\x63\x61llback_function\x18\x13 \x01(\t:\x19pb_default_field_callback\x12\x30\n\x0e\x64\x65scriptorsize\x18\x14 \x01(\x0e\x32\x0f.DescriptorSize:\x07\x44S_AUTO\x12\x1a\n\x0b\x64\x65\x66\x61ult_has\x18\x17 \x01(\x08:\x05\x66\x61lse\x12\x0f\n\x07include\x18\x18 \x03(\t\x12\x0f\n\x07\x65xclude\x18\x1a \x03(\t\x12\x0f\n\x07package\x18\x19 \x01(\t\x12\x41\n\rtype_override\x18\x1b \x01(\x0e\x32*.google.protobuf.FieldDescriptorProto.Type\x12\x19\n\x0bsort_by_tag\x18\x1c \x01(\x08:\x04true\x12.\n\rfallback_type\x18\x1d \x01(\x0e\x32\n.FieldType:\x0b\x46T_CALLBACK*i\n\tFieldType\x12\x0e\n\nFT_DEFAULT\x10\x00\x12\x0f\n\x0b\x46T_CALLBACK\x10\x01\x12\x0e\n\nFT_POINTER\x10\x04\x12\r\n\tFT_STATIC\x10\x02\x12\r\n\tFT_IGNORE\x10\x03\x12\r\n\tFT_INLINE\x10\x05*D\n\x07IntSize\x12\x0e\n\nIS_DEFAULT\x10\x00\x12\x08\n\x04IS_8\x10\x08\x12\t\n\x05IS_16\x10\x10\x12\t\n\x05IS_32\x10 \x12\t\n\x05IS_64\x10@*Z\n\x10TypenameMangling\x12\n\n\x06M_NONE\x10\x00\x12\x13\n\x0fM_STRIP_PACKAGE\x10\x01\x12\r\n\tM_FLATTEN\x10\x02\x12\x16\n\x12M_PACKAGE_INITIALS\x10\x03*E\n\x0e\x44\x65scriptorSize\x12\x0b\n\x07\x44S_AUTO\x10\x00\x12\x08\n\x04\x44S_1\x10\x01\x12\x08\n\x04\x44S_2\x10\x02\x12\x08\n\x04\x44S_4\x10\x04\x12\x08\n\x04\x44S_8\x10\x08:E\n\x0enanopb_fileopt\x12\x1c.google.protobuf.FileOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:G\n\rnanopb_msgopt\x12\x1f.google.protobuf.MessageOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:E\n\x0enanopb_enumopt\x12\x1c.google.protobuf.EnumOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:>\n\x06nanopb\x12\x1d.google.protobuf.FieldOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptionsB>\n\x18\x66i.kapsi.koti.jpa.nanopbZ\"github.com/meshtastic/go/generated')
|
||||||
|
|
||||||
|
_globals = globals()
|
||||||
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||||
|
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.nanopb_pb2', _globals)
|
||||||
|
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||||
|
DESCRIPTOR._options = None
|
||||||
|
DESCRIPTOR._serialized_options = b'\n\030fi.kapsi.koti.jpa.nanopbZ\"github.com/meshtastic/go/generated'
|
||||||
|
_globals['_FIELDTYPE']._serialized_start=1005
|
||||||
|
_globals['_FIELDTYPE']._serialized_end=1110
|
||||||
|
_globals['_INTSIZE']._serialized_start=1112
|
||||||
|
_globals['_INTSIZE']._serialized_end=1180
|
||||||
|
_globals['_TYPENAMEMANGLING']._serialized_start=1182
|
||||||
|
_globals['_TYPENAMEMANGLING']._serialized_end=1272
|
||||||
|
_globals['_DESCRIPTORSIZE']._serialized_start=1274
|
||||||
|
_globals['_DESCRIPTORSIZE']._serialized_end=1343
|
||||||
|
_globals['_NANOPBOPTIONS']._serialized_start=71
|
||||||
|
_globals['_NANOPBOPTIONS']._serialized_end=1003
|
||||||
|
# @@protoc_insertion_point(module_scope)
|
||||||
324
meshtastic/protobuf/nanopb_pb2.pyi
generated
Normal file
324
meshtastic/protobuf/nanopb_pb2.pyi
generated
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
"""
|
||||||
|
@generated by mypy-protobuf. Do not edit manually!
|
||||||
|
isort:skip_file
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import builtins
|
||||||
|
import collections.abc
|
||||||
|
import google.protobuf.descriptor
|
||||||
|
import google.protobuf.descriptor_pb2
|
||||||
|
import google.protobuf.internal.containers
|
||||||
|
import google.protobuf.internal.enum_type_wrapper
|
||||||
|
import google.protobuf.internal.extension_dict
|
||||||
|
import google.protobuf.message
|
||||||
|
import sys
|
||||||
|
import typing
|
||||||
|
|
||||||
|
if sys.version_info >= (3, 10):
|
||||||
|
import typing as typing_extensions
|
||||||
|
else:
|
||||||
|
import typing_extensions
|
||||||
|
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
|
||||||
|
|
||||||
|
class _FieldType:
|
||||||
|
ValueType = typing.NewType("ValueType", builtins.int)
|
||||||
|
V: typing_extensions.TypeAlias = ValueType
|
||||||
|
|
||||||
|
class _FieldTypeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_FieldType.ValueType], builtins.type):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
|
||||||
|
FT_DEFAULT: _FieldType.ValueType # 0
|
||||||
|
"""Automatically decide field type, generate static field if possible."""
|
||||||
|
FT_CALLBACK: _FieldType.ValueType # 1
|
||||||
|
"""Always generate a callback field."""
|
||||||
|
FT_POINTER: _FieldType.ValueType # 4
|
||||||
|
"""Always generate a dynamically allocated field."""
|
||||||
|
FT_STATIC: _FieldType.ValueType # 2
|
||||||
|
"""Generate a static field or raise an exception if not possible."""
|
||||||
|
FT_IGNORE: _FieldType.ValueType # 3
|
||||||
|
"""Ignore the field completely."""
|
||||||
|
FT_INLINE: _FieldType.ValueType # 5
|
||||||
|
"""Legacy option, use the separate 'fixed_length' option instead"""
|
||||||
|
|
||||||
|
class FieldType(_FieldType, metaclass=_FieldTypeEnumTypeWrapper): ...
|
||||||
|
|
||||||
|
FT_DEFAULT: FieldType.ValueType # 0
|
||||||
|
"""Automatically decide field type, generate static field if possible."""
|
||||||
|
FT_CALLBACK: FieldType.ValueType # 1
|
||||||
|
"""Always generate a callback field."""
|
||||||
|
FT_POINTER: FieldType.ValueType # 4
|
||||||
|
"""Always generate a dynamically allocated field."""
|
||||||
|
FT_STATIC: FieldType.ValueType # 2
|
||||||
|
"""Generate a static field or raise an exception if not possible."""
|
||||||
|
FT_IGNORE: FieldType.ValueType # 3
|
||||||
|
"""Ignore the field completely."""
|
||||||
|
FT_INLINE: FieldType.ValueType # 5
|
||||||
|
"""Legacy option, use the separate 'fixed_length' option instead"""
|
||||||
|
global___FieldType = FieldType
|
||||||
|
|
||||||
|
class _IntSize:
|
||||||
|
ValueType = typing.NewType("ValueType", builtins.int)
|
||||||
|
V: typing_extensions.TypeAlias = ValueType
|
||||||
|
|
||||||
|
class _IntSizeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_IntSize.ValueType], builtins.type):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
|
||||||
|
IS_DEFAULT: _IntSize.ValueType # 0
|
||||||
|
"""Default, 32/64bit based on type in .proto"""
|
||||||
|
IS_8: _IntSize.ValueType # 8
|
||||||
|
IS_16: _IntSize.ValueType # 16
|
||||||
|
IS_32: _IntSize.ValueType # 32
|
||||||
|
IS_64: _IntSize.ValueType # 64
|
||||||
|
|
||||||
|
class IntSize(_IntSize, metaclass=_IntSizeEnumTypeWrapper): ...
|
||||||
|
|
||||||
|
IS_DEFAULT: IntSize.ValueType # 0
|
||||||
|
"""Default, 32/64bit based on type in .proto"""
|
||||||
|
IS_8: IntSize.ValueType # 8
|
||||||
|
IS_16: IntSize.ValueType # 16
|
||||||
|
IS_32: IntSize.ValueType # 32
|
||||||
|
IS_64: IntSize.ValueType # 64
|
||||||
|
global___IntSize = IntSize
|
||||||
|
|
||||||
|
class _TypenameMangling:
|
||||||
|
ValueType = typing.NewType("ValueType", builtins.int)
|
||||||
|
V: typing_extensions.TypeAlias = ValueType
|
||||||
|
|
||||||
|
class _TypenameManglingEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_TypenameMangling.ValueType], builtins.type):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
|
||||||
|
M_NONE: _TypenameMangling.ValueType # 0
|
||||||
|
"""Default, no typename mangling"""
|
||||||
|
M_STRIP_PACKAGE: _TypenameMangling.ValueType # 1
|
||||||
|
"""Strip current package name"""
|
||||||
|
M_FLATTEN: _TypenameMangling.ValueType # 2
|
||||||
|
"""Only use last path component"""
|
||||||
|
M_PACKAGE_INITIALS: _TypenameMangling.ValueType # 3
|
||||||
|
"""Replace the package name by the initials"""
|
||||||
|
|
||||||
|
class TypenameMangling(_TypenameMangling, metaclass=_TypenameManglingEnumTypeWrapper): ...
|
||||||
|
|
||||||
|
M_NONE: TypenameMangling.ValueType # 0
|
||||||
|
"""Default, no typename mangling"""
|
||||||
|
M_STRIP_PACKAGE: TypenameMangling.ValueType # 1
|
||||||
|
"""Strip current package name"""
|
||||||
|
M_FLATTEN: TypenameMangling.ValueType # 2
|
||||||
|
"""Only use last path component"""
|
||||||
|
M_PACKAGE_INITIALS: TypenameMangling.ValueType # 3
|
||||||
|
"""Replace the package name by the initials"""
|
||||||
|
global___TypenameMangling = TypenameMangling
|
||||||
|
|
||||||
|
class _DescriptorSize:
|
||||||
|
ValueType = typing.NewType("ValueType", builtins.int)
|
||||||
|
V: typing_extensions.TypeAlias = ValueType
|
||||||
|
|
||||||
|
class _DescriptorSizeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_DescriptorSize.ValueType], builtins.type):
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
|
||||||
|
DS_AUTO: _DescriptorSize.ValueType # 0
|
||||||
|
"""Select minimal size based on field type"""
|
||||||
|
DS_1: _DescriptorSize.ValueType # 1
|
||||||
|
"""1 word; up to 15 byte fields, no arrays"""
|
||||||
|
DS_2: _DescriptorSize.ValueType # 2
|
||||||
|
"""2 words; up to 4095 byte fields, 4095 entry arrays"""
|
||||||
|
DS_4: _DescriptorSize.ValueType # 4
|
||||||
|
"""4 words; up to 2^32-1 byte fields, 2^16-1 entry arrays"""
|
||||||
|
DS_8: _DescriptorSize.ValueType # 8
|
||||||
|
"""8 words; up to 2^32-1 entry arrays"""
|
||||||
|
|
||||||
|
class DescriptorSize(_DescriptorSize, metaclass=_DescriptorSizeEnumTypeWrapper): ...
|
||||||
|
|
||||||
|
DS_AUTO: DescriptorSize.ValueType # 0
|
||||||
|
"""Select minimal size based on field type"""
|
||||||
|
DS_1: DescriptorSize.ValueType # 1
|
||||||
|
"""1 word; up to 15 byte fields, no arrays"""
|
||||||
|
DS_2: DescriptorSize.ValueType # 2
|
||||||
|
"""2 words; up to 4095 byte fields, 4095 entry arrays"""
|
||||||
|
DS_4: DescriptorSize.ValueType # 4
|
||||||
|
"""4 words; up to 2^32-1 byte fields, 2^16-1 entry arrays"""
|
||||||
|
DS_8: DescriptorSize.ValueType # 8
|
||||||
|
"""8 words; up to 2^32-1 entry arrays"""
|
||||||
|
global___DescriptorSize = DescriptorSize
|
||||||
|
|
||||||
|
@typing.final
|
||||||
|
class NanoPBOptions(google.protobuf.message.Message):
|
||||||
|
"""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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||||
|
|
||||||
|
MAX_SIZE_FIELD_NUMBER: builtins.int
|
||||||
|
MAX_LENGTH_FIELD_NUMBER: builtins.int
|
||||||
|
MAX_COUNT_FIELD_NUMBER: builtins.int
|
||||||
|
INT_SIZE_FIELD_NUMBER: builtins.int
|
||||||
|
TYPE_FIELD_NUMBER: builtins.int
|
||||||
|
LONG_NAMES_FIELD_NUMBER: builtins.int
|
||||||
|
PACKED_STRUCT_FIELD_NUMBER: builtins.int
|
||||||
|
PACKED_ENUM_FIELD_NUMBER: builtins.int
|
||||||
|
SKIP_MESSAGE_FIELD_NUMBER: builtins.int
|
||||||
|
NO_UNIONS_FIELD_NUMBER: builtins.int
|
||||||
|
MSGID_FIELD_NUMBER: builtins.int
|
||||||
|
ANONYMOUS_ONEOF_FIELD_NUMBER: builtins.int
|
||||||
|
PROTO3_FIELD_NUMBER: builtins.int
|
||||||
|
PROTO3_SINGULAR_MSGS_FIELD_NUMBER: builtins.int
|
||||||
|
ENUM_TO_STRING_FIELD_NUMBER: builtins.int
|
||||||
|
FIXED_LENGTH_FIELD_NUMBER: builtins.int
|
||||||
|
FIXED_COUNT_FIELD_NUMBER: builtins.int
|
||||||
|
SUBMSG_CALLBACK_FIELD_NUMBER: builtins.int
|
||||||
|
MANGLE_NAMES_FIELD_NUMBER: builtins.int
|
||||||
|
CALLBACK_DATATYPE_FIELD_NUMBER: builtins.int
|
||||||
|
CALLBACK_FUNCTION_FIELD_NUMBER: builtins.int
|
||||||
|
DESCRIPTORSIZE_FIELD_NUMBER: builtins.int
|
||||||
|
DEFAULT_HAS_FIELD_NUMBER: builtins.int
|
||||||
|
INCLUDE_FIELD_NUMBER: builtins.int
|
||||||
|
EXCLUDE_FIELD_NUMBER: builtins.int
|
||||||
|
PACKAGE_FIELD_NUMBER: builtins.int
|
||||||
|
TYPE_OVERRIDE_FIELD_NUMBER: builtins.int
|
||||||
|
SORT_BY_TAG_FIELD_NUMBER: builtins.int
|
||||||
|
FALLBACK_TYPE_FIELD_NUMBER: builtins.int
|
||||||
|
max_size: builtins.int
|
||||||
|
"""Allocated size for 'bytes' and 'string' fields.
|
||||||
|
For string fields, this should include the space for null terminator.
|
||||||
|
"""
|
||||||
|
max_length: builtins.int
|
||||||
|
"""Maximum length for 'string' fields. Setting this is equivalent
|
||||||
|
to setting max_size to a value of length+1.
|
||||||
|
"""
|
||||||
|
max_count: builtins.int
|
||||||
|
"""Allocated number of entries in arrays ('repeated' fields)"""
|
||||||
|
int_size: global___IntSize.ValueType
|
||||||
|
"""Size of integer fields. Can save some memory if you don't need
|
||||||
|
full 32 bits for the value.
|
||||||
|
"""
|
||||||
|
type: global___FieldType.ValueType
|
||||||
|
"""Force type of field (callback or static allocation)"""
|
||||||
|
long_names: builtins.bool
|
||||||
|
"""Use long names for enums, i.e. EnumName_EnumValue."""
|
||||||
|
packed_struct: builtins.bool
|
||||||
|
"""Add 'packed' attribute to generated structs.
|
||||||
|
Note: this cannot be used on CPUs that break on unaligned
|
||||||
|
accesses to variables.
|
||||||
|
"""
|
||||||
|
packed_enum: builtins.bool
|
||||||
|
"""Add 'packed' attribute to generated enums."""
|
||||||
|
skip_message: builtins.bool
|
||||||
|
"""Skip this message"""
|
||||||
|
no_unions: builtins.bool
|
||||||
|
"""Generate oneof fields as normal optional fields instead of union."""
|
||||||
|
msgid: builtins.int
|
||||||
|
"""integer type tag for a message"""
|
||||||
|
anonymous_oneof: builtins.bool
|
||||||
|
"""decode oneof as anonymous union"""
|
||||||
|
proto3: builtins.bool
|
||||||
|
"""Proto3 singular field does not generate a "has_" flag"""
|
||||||
|
proto3_singular_msgs: builtins.bool
|
||||||
|
"""Force proto3 messages to have no "has_" flag.
|
||||||
|
This was default behavior until nanopb-0.4.0.
|
||||||
|
"""
|
||||||
|
enum_to_string: builtins.bool
|
||||||
|
"""Generate an enum->string mapping function (can take up lots of space)."""
|
||||||
|
fixed_length: builtins.bool
|
||||||
|
"""Generate bytes arrays with fixed length"""
|
||||||
|
fixed_count: builtins.bool
|
||||||
|
"""Generate repeated field with fixed count"""
|
||||||
|
submsg_callback: builtins.bool
|
||||||
|
"""Generate message-level callback that is called before decoding submessages.
|
||||||
|
This can be used to set callback fields for submsgs inside oneofs.
|
||||||
|
"""
|
||||||
|
mangle_names: global___TypenameMangling.ValueType
|
||||||
|
"""Shorten or remove package names from type names.
|
||||||
|
This option applies only on the file level.
|
||||||
|
"""
|
||||||
|
callback_datatype: builtins.str
|
||||||
|
"""Data type for storage associated with callback fields."""
|
||||||
|
callback_function: builtins.str
|
||||||
|
"""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.
|
||||||
|
"""
|
||||||
|
descriptorsize: global___DescriptorSize.ValueType
|
||||||
|
"""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.
|
||||||
|
"""
|
||||||
|
default_has: builtins.bool
|
||||||
|
"""Set default value for has_ fields."""
|
||||||
|
package: builtins.str
|
||||||
|
"""Package name that applies only for nanopb."""
|
||||||
|
type_override: google.protobuf.descriptor_pb2.FieldDescriptorProto.Type.ValueType
|
||||||
|
"""Override type of the field in generated C code. Only to be used with related field types"""
|
||||||
|
sort_by_tag: builtins.bool
|
||||||
|
"""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.
|
||||||
|
"""
|
||||||
|
fallback_type: global___FieldType.ValueType
|
||||||
|
"""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.
|
||||||
|
"""
|
||||||
|
@property
|
||||||
|
def include(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]:
|
||||||
|
"""Extra files to include in generated `.pb.h`"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def exclude(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]:
|
||||||
|
"""Automatic includes to exclude from generated `.pb.h`
|
||||||
|
Same as nanopb_generator.py command line flag -x.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
max_size: builtins.int | None = ...,
|
||||||
|
max_length: builtins.int | None = ...,
|
||||||
|
max_count: builtins.int | None = ...,
|
||||||
|
int_size: global___IntSize.ValueType | None = ...,
|
||||||
|
type: global___FieldType.ValueType | None = ...,
|
||||||
|
long_names: builtins.bool | None = ...,
|
||||||
|
packed_struct: builtins.bool | None = ...,
|
||||||
|
packed_enum: builtins.bool | None = ...,
|
||||||
|
skip_message: builtins.bool | None = ...,
|
||||||
|
no_unions: builtins.bool | None = ...,
|
||||||
|
msgid: builtins.int | None = ...,
|
||||||
|
anonymous_oneof: builtins.bool | None = ...,
|
||||||
|
proto3: builtins.bool | None = ...,
|
||||||
|
proto3_singular_msgs: builtins.bool | None = ...,
|
||||||
|
enum_to_string: builtins.bool | None = ...,
|
||||||
|
fixed_length: builtins.bool | None = ...,
|
||||||
|
fixed_count: builtins.bool | None = ...,
|
||||||
|
submsg_callback: builtins.bool | None = ...,
|
||||||
|
mangle_names: global___TypenameMangling.ValueType | None = ...,
|
||||||
|
callback_datatype: builtins.str | None = ...,
|
||||||
|
callback_function: builtins.str | None = ...,
|
||||||
|
descriptorsize: global___DescriptorSize.ValueType | None = ...,
|
||||||
|
default_has: builtins.bool | None = ...,
|
||||||
|
include: collections.abc.Iterable[builtins.str] | None = ...,
|
||||||
|
exclude: collections.abc.Iterable[builtins.str] | None = ...,
|
||||||
|
package: builtins.str | None = ...,
|
||||||
|
type_override: google.protobuf.descriptor_pb2.FieldDescriptorProto.Type.ValueType | None = ...,
|
||||||
|
sort_by_tag: builtins.bool | None = ...,
|
||||||
|
fallback_type: global___FieldType.ValueType | None = ...,
|
||||||
|
) -> None: ...
|
||||||
|
def HasField(self, field_name: typing.Literal["anonymous_oneof", b"anonymous_oneof", "callback_datatype", b"callback_datatype", "callback_function", b"callback_function", "default_has", b"default_has", "descriptorsize", b"descriptorsize", "enum_to_string", b"enum_to_string", "fallback_type", b"fallback_type", "fixed_count", b"fixed_count", "fixed_length", b"fixed_length", "int_size", b"int_size", "long_names", b"long_names", "mangle_names", b"mangle_names", "max_count", b"max_count", "max_length", b"max_length", "max_size", b"max_size", "msgid", b"msgid", "no_unions", b"no_unions", "package", b"package", "packed_enum", b"packed_enum", "packed_struct", b"packed_struct", "proto3", b"proto3", "proto3_singular_msgs", b"proto3_singular_msgs", "skip_message", b"skip_message", "sort_by_tag", b"sort_by_tag", "submsg_callback", b"submsg_callback", "type", b"type", "type_override", b"type_override"]) -> builtins.bool: ...
|
||||||
|
def ClearField(self, field_name: typing.Literal["anonymous_oneof", b"anonymous_oneof", "callback_datatype", b"callback_datatype", "callback_function", b"callback_function", "default_has", b"default_has", "descriptorsize", b"descriptorsize", "enum_to_string", b"enum_to_string", "exclude", b"exclude", "fallback_type", b"fallback_type", "fixed_count", b"fixed_count", "fixed_length", b"fixed_length", "include", b"include", "int_size", b"int_size", "long_names", b"long_names", "mangle_names", b"mangle_names", "max_count", b"max_count", "max_length", b"max_length", "max_size", b"max_size", "msgid", b"msgid", "no_unions", b"no_unions", "package", b"package", "packed_enum", b"packed_enum", "packed_struct", b"packed_struct", "proto3", b"proto3", "proto3_singular_msgs", b"proto3_singular_msgs", "skip_message", b"skip_message", "sort_by_tag", b"sort_by_tag", "submsg_callback", b"submsg_callback", "type", b"type", "type_override", b"type_override"]) -> None: ...
|
||||||
|
|
||||||
|
global___NanoPBOptions = NanoPBOptions
|
||||||
|
|
||||||
|
NANOPB_FILEOPT_FIELD_NUMBER: builtins.int
|
||||||
|
NANOPB_MSGOPT_FIELD_NUMBER: builtins.int
|
||||||
|
NANOPB_ENUMOPT_FIELD_NUMBER: builtins.int
|
||||||
|
NANOPB_FIELD_NUMBER: builtins.int
|
||||||
|
nanopb_fileopt: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.FileOptions, global___NanoPBOptions]
|
||||||
|
nanopb_msgopt: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.MessageOptions, global___NanoPBOptions]
|
||||||
|
nanopb_enumopt: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.EnumOptions, global___NanoPBOptions]
|
||||||
|
nanopb: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.FieldOptions, global___NanoPBOptions]
|
||||||
4
meshtastic/protobuf/portnums_pb2.py
generated
4
meshtastic/protobuf/portnums_pb2.py
generated
@@ -13,7 +13,7 @@ _sym_db = _symbol_database.Default()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\"meshtastic/protobuf/portnums.proto\x12\x13meshtastic.protobuf*\xa2\x04\n\x07PortNum\x12\x0f\n\x0bUNKNOWN_APP\x10\x00\x12\x14\n\x10TEXT_MESSAGE_APP\x10\x01\x12\x17\n\x13REMOTE_HARDWARE_APP\x10\x02\x12\x10\n\x0cPOSITION_APP\x10\x03\x12\x10\n\x0cNODEINFO_APP\x10\x04\x12\x0f\n\x0bROUTING_APP\x10\x05\x12\r\n\tADMIN_APP\x10\x06\x12\x1f\n\x1bTEXT_MESSAGE_COMPRESSED_APP\x10\x07\x12\x10\n\x0cWAYPOINT_APP\x10\x08\x12\r\n\tAUDIO_APP\x10\t\x12\x18\n\x14\x44\x45TECTION_SENSOR_APP\x10\n\x12\r\n\tREPLY_APP\x10 \x12\x11\n\rIP_TUNNEL_APP\x10!\x12\x12\n\x0ePAXCOUNTER_APP\x10\"\x12\x0e\n\nSERIAL_APP\x10@\x12\x15\n\x11STORE_FORWARD_APP\x10\x41\x12\x12\n\x0eRANGE_TEST_APP\x10\x42\x12\x11\n\rTELEMETRY_APP\x10\x43\x12\x0b\n\x07ZPS_APP\x10\x44\x12\x11\n\rSIMULATOR_APP\x10\x45\x12\x12\n\x0eTRACEROUTE_APP\x10\x46\x12\x14\n\x10NEIGHBORINFO_APP\x10G\x12\x0f\n\x0b\x41TAK_PLUGIN\x10H\x12\x12\n\x0eMAP_REPORT_APP\x10I\x12\x13\n\x0fPOWERSTRESS_APP\x10J\x12\x10\n\x0bPRIVATE_APP\x10\x80\x02\x12\x13\n\x0e\x41TAK_FORWARDER\x10\x81\x02\x12\x08\n\x03MAX\x10\xff\x03\x42]\n\x13\x63om.geeksville.meshB\x08PortnumsZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\"meshtastic/protobuf/portnums.proto\x12\x13meshtastic.protobuf*\xf6\x04\n\x07PortNum\x12\x0f\n\x0bUNKNOWN_APP\x10\x00\x12\x14\n\x10TEXT_MESSAGE_APP\x10\x01\x12\x17\n\x13REMOTE_HARDWARE_APP\x10\x02\x12\x10\n\x0cPOSITION_APP\x10\x03\x12\x10\n\x0cNODEINFO_APP\x10\x04\x12\x0f\n\x0bROUTING_APP\x10\x05\x12\r\n\tADMIN_APP\x10\x06\x12\x1f\n\x1bTEXT_MESSAGE_COMPRESSED_APP\x10\x07\x12\x10\n\x0cWAYPOINT_APP\x10\x08\x12\r\n\tAUDIO_APP\x10\t\x12\x18\n\x14\x44\x45TECTION_SENSOR_APP\x10\n\x12\r\n\tALERT_APP\x10\x0b\x12\x18\n\x14KEY_VERIFICATION_APP\x10\x0c\x12\r\n\tREPLY_APP\x10 \x12\x11\n\rIP_TUNNEL_APP\x10!\x12\x12\n\x0ePAXCOUNTER_APP\x10\"\x12\x0e\n\nSERIAL_APP\x10@\x12\x15\n\x11STORE_FORWARD_APP\x10\x41\x12\x12\n\x0eRANGE_TEST_APP\x10\x42\x12\x11\n\rTELEMETRY_APP\x10\x43\x12\x0b\n\x07ZPS_APP\x10\x44\x12\x11\n\rSIMULATOR_APP\x10\x45\x12\x12\n\x0eTRACEROUTE_APP\x10\x46\x12\x14\n\x10NEIGHBORINFO_APP\x10G\x12\x0f\n\x0b\x41TAK_PLUGIN\x10H\x12\x12\n\x0eMAP_REPORT_APP\x10I\x12\x13\n\x0fPOWERSTRESS_APP\x10J\x12\x18\n\x14RETICULUM_TUNNEL_APP\x10L\x12\x0f\n\x0b\x43\x41YENNE_APP\x10M\x12\x10\n\x0bPRIVATE_APP\x10\x80\x02\x12\x13\n\x0e\x41TAK_FORWARDER\x10\x81\x02\x12\x08\n\x03MAX\x10\xff\x03\x42]\n\x13\x63om.geeksville.meshB\x08PortnumsZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||||
|
|
||||||
_globals = globals()
|
_globals = globals()
|
||||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||||
@@ -22,5 +22,5 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|||||||
DESCRIPTOR._options = None
|
DESCRIPTOR._options = None
|
||||||
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\010PortnumsZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
|
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\010PortnumsZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
|
||||||
_globals['_PORTNUM']._serialized_start=60
|
_globals['_PORTNUM']._serialized_start=60
|
||||||
_globals['_PORTNUM']._serialized_end=606
|
_globals['_PORTNUM']._serialized_end=690
|
||||||
# @@protoc_insertion_point(module_scope)
|
# @@protoc_insertion_point(module_scope)
|
||||||
|
|||||||
38
meshtastic/protobuf/portnums_pb2.pyi
generated
38
meshtastic/protobuf/portnums_pb2.pyi
generated
@@ -93,6 +93,14 @@ class _PortNumEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTy
|
|||||||
Same as Text Message but originating from Detection Sensor Module.
|
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
|
NOTE: This portnum traffic is not sent to the public MQTT starting at firmware version 2.2.9
|
||||||
"""
|
"""
|
||||||
|
ALERT_APP: _PortNum.ValueType # 11
|
||||||
|
"""
|
||||||
|
Same as Text Message but used for critical alerts.
|
||||||
|
"""
|
||||||
|
KEY_VERIFICATION_APP: _PortNum.ValueType # 12
|
||||||
|
"""
|
||||||
|
Module/port for handling key verification requests.
|
||||||
|
"""
|
||||||
REPLY_APP: _PortNum.ValueType # 32
|
REPLY_APP: _PortNum.ValueType # 32
|
||||||
"""
|
"""
|
||||||
Provides a 'ping' service that replies to any packet it receives.
|
Provides a 'ping' service that replies to any packet it receives.
|
||||||
@@ -175,6 +183,17 @@ class _PortNumEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTy
|
|||||||
"""
|
"""
|
||||||
PowerStress based monitoring support (for automated power consumption testing)
|
PowerStress based monitoring support (for automated power consumption testing)
|
||||||
"""
|
"""
|
||||||
|
RETICULUM_TUNNEL_APP: _PortNum.ValueType # 76
|
||||||
|
"""
|
||||||
|
Reticulum Network Stack Tunnel App
|
||||||
|
ENCODING: Fragmented RNS Packet. Handled by Meshtastic RNS interface
|
||||||
|
"""
|
||||||
|
CAYENNE_APP: _PortNum.ValueType # 77
|
||||||
|
"""
|
||||||
|
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
|
||||||
|
"""
|
||||||
PRIVATE_APP: _PortNum.ValueType # 256
|
PRIVATE_APP: _PortNum.ValueType # 256
|
||||||
"""
|
"""
|
||||||
Private applications should use portnums >= 256.
|
Private applications should use portnums >= 256.
|
||||||
@@ -278,6 +297,14 @@ DETECTION_SENSOR_APP: PortNum.ValueType # 10
|
|||||||
Same as Text Message but originating from Detection Sensor Module.
|
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
|
NOTE: This portnum traffic is not sent to the public MQTT starting at firmware version 2.2.9
|
||||||
"""
|
"""
|
||||||
|
ALERT_APP: PortNum.ValueType # 11
|
||||||
|
"""
|
||||||
|
Same as Text Message but used for critical alerts.
|
||||||
|
"""
|
||||||
|
KEY_VERIFICATION_APP: PortNum.ValueType # 12
|
||||||
|
"""
|
||||||
|
Module/port for handling key verification requests.
|
||||||
|
"""
|
||||||
REPLY_APP: PortNum.ValueType # 32
|
REPLY_APP: PortNum.ValueType # 32
|
||||||
"""
|
"""
|
||||||
Provides a 'ping' service that replies to any packet it receives.
|
Provides a 'ping' service that replies to any packet it receives.
|
||||||
@@ -360,6 +387,17 @@ POWERSTRESS_APP: PortNum.ValueType # 74
|
|||||||
"""
|
"""
|
||||||
PowerStress based monitoring support (for automated power consumption testing)
|
PowerStress based monitoring support (for automated power consumption testing)
|
||||||
"""
|
"""
|
||||||
|
RETICULUM_TUNNEL_APP: PortNum.ValueType # 76
|
||||||
|
"""
|
||||||
|
Reticulum Network Stack Tunnel App
|
||||||
|
ENCODING: Fragmented RNS Packet. Handled by Meshtastic RNS interface
|
||||||
|
"""
|
||||||
|
CAYENNE_APP: PortNum.ValueType # 77
|
||||||
|
"""
|
||||||
|
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
|
||||||
|
"""
|
||||||
PRIVATE_APP: PortNum.ValueType # 256
|
PRIVATE_APP: PortNum.ValueType # 256
|
||||||
"""
|
"""
|
||||||
Private applications should use portnums >= 256.
|
Private applications should use portnums >= 256.
|
||||||
|
|||||||
32
meshtastic/protobuf/telemetry_pb2.py
generated
32
meshtastic/protobuf/telemetry_pb2.py
generated
File diff suppressed because one or more lines are too long
557
meshtastic/protobuf/telemetry_pb2.pyi
generated
557
meshtastic/protobuf/telemetry_pb2.pyi
generated
@@ -143,6 +143,66 @@ class _TelemetrySensorTypeEnumTypeWrapper(google.protobuf.internal.enum_type_wra
|
|||||||
"""
|
"""
|
||||||
Custom I2C sensor implementation based on https://github.com/meshtastic/i2c-sensor
|
Custom I2C sensor implementation based on https://github.com/meshtastic/i2c-sensor
|
||||||
"""
|
"""
|
||||||
|
MAX30102: _TelemetrySensorType.ValueType # 30
|
||||||
|
"""
|
||||||
|
MAX30102 Pulse Oximeter and Heart-Rate Sensor
|
||||||
|
"""
|
||||||
|
MLX90614: _TelemetrySensorType.ValueType # 31
|
||||||
|
"""
|
||||||
|
MLX90614 non-contact IR temperature sensor
|
||||||
|
"""
|
||||||
|
SCD4X: _TelemetrySensorType.ValueType # 32
|
||||||
|
"""
|
||||||
|
SCD40/SCD41 CO2, humidity, temperature sensor
|
||||||
|
"""
|
||||||
|
RADSENS: _TelemetrySensorType.ValueType # 33
|
||||||
|
"""
|
||||||
|
ClimateGuard RadSens, radiation, Geiger-Muller Tube
|
||||||
|
"""
|
||||||
|
INA226: _TelemetrySensorType.ValueType # 34
|
||||||
|
"""
|
||||||
|
High accuracy current and voltage
|
||||||
|
"""
|
||||||
|
DFROBOT_RAIN: _TelemetrySensorType.ValueType # 35
|
||||||
|
"""
|
||||||
|
DFRobot Gravity tipping bucket rain gauge
|
||||||
|
"""
|
||||||
|
DPS310: _TelemetrySensorType.ValueType # 36
|
||||||
|
"""
|
||||||
|
Infineon DPS310 High accuracy pressure and temperature
|
||||||
|
"""
|
||||||
|
RAK12035: _TelemetrySensorType.ValueType # 37
|
||||||
|
"""
|
||||||
|
RAKWireless RAK12035 Soil Moisture Sensor Module
|
||||||
|
"""
|
||||||
|
MAX17261: _TelemetrySensorType.ValueType # 38
|
||||||
|
"""
|
||||||
|
MAX17261 lipo battery gauge
|
||||||
|
"""
|
||||||
|
PCT2075: _TelemetrySensorType.ValueType # 39
|
||||||
|
"""
|
||||||
|
PCT2075 Temperature Sensor
|
||||||
|
"""
|
||||||
|
ADS1X15: _TelemetrySensorType.ValueType # 40
|
||||||
|
"""
|
||||||
|
ADS1X15 ADC
|
||||||
|
"""
|
||||||
|
ADS1X15_ALT: _TelemetrySensorType.ValueType # 41
|
||||||
|
"""
|
||||||
|
ADS1X15 ADC_ALT
|
||||||
|
"""
|
||||||
|
SFA30: _TelemetrySensorType.ValueType # 42
|
||||||
|
"""
|
||||||
|
Sensirion SFA30 Formaldehyde sensor
|
||||||
|
"""
|
||||||
|
SEN5X: _TelemetrySensorType.ValueType # 43
|
||||||
|
"""
|
||||||
|
SEN5X PM SENSORS
|
||||||
|
"""
|
||||||
|
TSL2561: _TelemetrySensorType.ValueType # 44
|
||||||
|
"""
|
||||||
|
TSL2561 light sensor
|
||||||
|
"""
|
||||||
|
|
||||||
class TelemetrySensorType(_TelemetrySensorType, metaclass=_TelemetrySensorTypeEnumTypeWrapper):
|
class TelemetrySensorType(_TelemetrySensorType, metaclass=_TelemetrySensorTypeEnumTypeWrapper):
|
||||||
"""
|
"""
|
||||||
@@ -269,6 +329,66 @@ CUSTOM_SENSOR: TelemetrySensorType.ValueType # 29
|
|||||||
"""
|
"""
|
||||||
Custom I2C sensor implementation based on https://github.com/meshtastic/i2c-sensor
|
Custom I2C sensor implementation based on https://github.com/meshtastic/i2c-sensor
|
||||||
"""
|
"""
|
||||||
|
MAX30102: TelemetrySensorType.ValueType # 30
|
||||||
|
"""
|
||||||
|
MAX30102 Pulse Oximeter and Heart-Rate Sensor
|
||||||
|
"""
|
||||||
|
MLX90614: TelemetrySensorType.ValueType # 31
|
||||||
|
"""
|
||||||
|
MLX90614 non-contact IR temperature sensor
|
||||||
|
"""
|
||||||
|
SCD4X: TelemetrySensorType.ValueType # 32
|
||||||
|
"""
|
||||||
|
SCD40/SCD41 CO2, humidity, temperature sensor
|
||||||
|
"""
|
||||||
|
RADSENS: TelemetrySensorType.ValueType # 33
|
||||||
|
"""
|
||||||
|
ClimateGuard RadSens, radiation, Geiger-Muller Tube
|
||||||
|
"""
|
||||||
|
INA226: TelemetrySensorType.ValueType # 34
|
||||||
|
"""
|
||||||
|
High accuracy current and voltage
|
||||||
|
"""
|
||||||
|
DFROBOT_RAIN: TelemetrySensorType.ValueType # 35
|
||||||
|
"""
|
||||||
|
DFRobot Gravity tipping bucket rain gauge
|
||||||
|
"""
|
||||||
|
DPS310: TelemetrySensorType.ValueType # 36
|
||||||
|
"""
|
||||||
|
Infineon DPS310 High accuracy pressure and temperature
|
||||||
|
"""
|
||||||
|
RAK12035: TelemetrySensorType.ValueType # 37
|
||||||
|
"""
|
||||||
|
RAKWireless RAK12035 Soil Moisture Sensor Module
|
||||||
|
"""
|
||||||
|
MAX17261: TelemetrySensorType.ValueType # 38
|
||||||
|
"""
|
||||||
|
MAX17261 lipo battery gauge
|
||||||
|
"""
|
||||||
|
PCT2075: TelemetrySensorType.ValueType # 39
|
||||||
|
"""
|
||||||
|
PCT2075 Temperature Sensor
|
||||||
|
"""
|
||||||
|
ADS1X15: TelemetrySensorType.ValueType # 40
|
||||||
|
"""
|
||||||
|
ADS1X15 ADC
|
||||||
|
"""
|
||||||
|
ADS1X15_ALT: TelemetrySensorType.ValueType # 41
|
||||||
|
"""
|
||||||
|
ADS1X15 ADC_ALT
|
||||||
|
"""
|
||||||
|
SFA30: TelemetrySensorType.ValueType # 42
|
||||||
|
"""
|
||||||
|
Sensirion SFA30 Formaldehyde sensor
|
||||||
|
"""
|
||||||
|
SEN5X: TelemetrySensorType.ValueType # 43
|
||||||
|
"""
|
||||||
|
SEN5X PM SENSORS
|
||||||
|
"""
|
||||||
|
TSL2561: TelemetrySensorType.ValueType # 44
|
||||||
|
"""
|
||||||
|
TSL2561 light sensor
|
||||||
|
"""
|
||||||
global___TelemetrySensorType = TelemetrySensorType
|
global___TelemetrySensorType = TelemetrySensorType
|
||||||
|
|
||||||
@typing.final
|
@typing.final
|
||||||
@@ -353,6 +473,11 @@ class EnvironmentMetrics(google.protobuf.message.Message):
|
|||||||
WEIGHT_FIELD_NUMBER: builtins.int
|
WEIGHT_FIELD_NUMBER: builtins.int
|
||||||
WIND_GUST_FIELD_NUMBER: builtins.int
|
WIND_GUST_FIELD_NUMBER: builtins.int
|
||||||
WIND_LULL_FIELD_NUMBER: builtins.int
|
WIND_LULL_FIELD_NUMBER: builtins.int
|
||||||
|
RADIATION_FIELD_NUMBER: builtins.int
|
||||||
|
RAINFALL_1H_FIELD_NUMBER: builtins.int
|
||||||
|
RAINFALL_24H_FIELD_NUMBER: builtins.int
|
||||||
|
SOIL_MOISTURE_FIELD_NUMBER: builtins.int
|
||||||
|
SOIL_TEMPERATURE_FIELD_NUMBER: builtins.int
|
||||||
temperature: builtins.float
|
temperature: builtins.float
|
||||||
"""
|
"""
|
||||||
Temperature measured
|
Temperature measured
|
||||||
@@ -423,6 +548,26 @@ class EnvironmentMetrics(google.protobuf.message.Message):
|
|||||||
"""
|
"""
|
||||||
Wind lull in m/s
|
Wind lull in m/s
|
||||||
"""
|
"""
|
||||||
|
radiation: builtins.float
|
||||||
|
"""
|
||||||
|
Radiation in µR/h
|
||||||
|
"""
|
||||||
|
rainfall_1h: builtins.float
|
||||||
|
"""
|
||||||
|
Rainfall in the last hour in mm
|
||||||
|
"""
|
||||||
|
rainfall_24h: builtins.float
|
||||||
|
"""
|
||||||
|
Rainfall in the last 24 hours in mm
|
||||||
|
"""
|
||||||
|
soil_moisture: builtins.int
|
||||||
|
"""
|
||||||
|
Soil moisture measured (% 1-100)
|
||||||
|
"""
|
||||||
|
soil_temperature: builtins.float
|
||||||
|
"""
|
||||||
|
Soil temperature measured (*C)
|
||||||
|
"""
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
@@ -443,9 +588,14 @@ class EnvironmentMetrics(google.protobuf.message.Message):
|
|||||||
weight: builtins.float | None = ...,
|
weight: builtins.float | None = ...,
|
||||||
wind_gust: builtins.float | None = ...,
|
wind_gust: builtins.float | None = ...,
|
||||||
wind_lull: builtins.float | None = ...,
|
wind_lull: builtins.float | None = ...,
|
||||||
|
radiation: builtins.float | None = ...,
|
||||||
|
rainfall_1h: builtins.float | None = ...,
|
||||||
|
rainfall_24h: builtins.float | None = ...,
|
||||||
|
soil_moisture: builtins.int | None = ...,
|
||||||
|
soil_temperature: builtins.float | None = ...,
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
def HasField(self, field_name: typing.Literal["_barometric_pressure", b"_barometric_pressure", "_current", b"_current", "_distance", b"_distance", "_gas_resistance", b"_gas_resistance", "_iaq", b"_iaq", "_ir_lux", b"_ir_lux", "_lux", b"_lux", "_relative_humidity", b"_relative_humidity", "_temperature", b"_temperature", "_uv_lux", b"_uv_lux", "_voltage", b"_voltage", "_weight", b"_weight", "_white_lux", b"_white_lux", "_wind_direction", b"_wind_direction", "_wind_gust", b"_wind_gust", "_wind_lull", b"_wind_lull", "_wind_speed", b"_wind_speed", "barometric_pressure", b"barometric_pressure", "current", b"current", "distance", b"distance", "gas_resistance", b"gas_resistance", "iaq", b"iaq", "ir_lux", b"ir_lux", "lux", b"lux", "relative_humidity", b"relative_humidity", "temperature", b"temperature", "uv_lux", b"uv_lux", "voltage", b"voltage", "weight", b"weight", "white_lux", b"white_lux", "wind_direction", b"wind_direction", "wind_gust", b"wind_gust", "wind_lull", b"wind_lull", "wind_speed", b"wind_speed"]) -> builtins.bool: ...
|
def HasField(self, field_name: typing.Literal["_barometric_pressure", b"_barometric_pressure", "_current", b"_current", "_distance", b"_distance", "_gas_resistance", b"_gas_resistance", "_iaq", b"_iaq", "_ir_lux", b"_ir_lux", "_lux", b"_lux", "_radiation", b"_radiation", "_rainfall_1h", b"_rainfall_1h", "_rainfall_24h", b"_rainfall_24h", "_relative_humidity", b"_relative_humidity", "_soil_moisture", b"_soil_moisture", "_soil_temperature", b"_soil_temperature", "_temperature", b"_temperature", "_uv_lux", b"_uv_lux", "_voltage", b"_voltage", "_weight", b"_weight", "_white_lux", b"_white_lux", "_wind_direction", b"_wind_direction", "_wind_gust", b"_wind_gust", "_wind_lull", b"_wind_lull", "_wind_speed", b"_wind_speed", "barometric_pressure", b"barometric_pressure", "current", b"current", "distance", b"distance", "gas_resistance", b"gas_resistance", "iaq", b"iaq", "ir_lux", b"ir_lux", "lux", b"lux", "radiation", b"radiation", "rainfall_1h", b"rainfall_1h", "rainfall_24h", b"rainfall_24h", "relative_humidity", b"relative_humidity", "soil_moisture", b"soil_moisture", "soil_temperature", b"soil_temperature", "temperature", b"temperature", "uv_lux", b"uv_lux", "voltage", b"voltage", "weight", b"weight", "white_lux", b"white_lux", "wind_direction", b"wind_direction", "wind_gust", b"wind_gust", "wind_lull", b"wind_lull", "wind_speed", b"wind_speed"]) -> builtins.bool: ...
|
||||||
def ClearField(self, field_name: typing.Literal["_barometric_pressure", b"_barometric_pressure", "_current", b"_current", "_distance", b"_distance", "_gas_resistance", b"_gas_resistance", "_iaq", b"_iaq", "_ir_lux", b"_ir_lux", "_lux", b"_lux", "_relative_humidity", b"_relative_humidity", "_temperature", b"_temperature", "_uv_lux", b"_uv_lux", "_voltage", b"_voltage", "_weight", b"_weight", "_white_lux", b"_white_lux", "_wind_direction", b"_wind_direction", "_wind_gust", b"_wind_gust", "_wind_lull", b"_wind_lull", "_wind_speed", b"_wind_speed", "barometric_pressure", b"barometric_pressure", "current", b"current", "distance", b"distance", "gas_resistance", b"gas_resistance", "iaq", b"iaq", "ir_lux", b"ir_lux", "lux", b"lux", "relative_humidity", b"relative_humidity", "temperature", b"temperature", "uv_lux", b"uv_lux", "voltage", b"voltage", "weight", b"weight", "white_lux", b"white_lux", "wind_direction", b"wind_direction", "wind_gust", b"wind_gust", "wind_lull", b"wind_lull", "wind_speed", b"wind_speed"]) -> None: ...
|
def ClearField(self, field_name: typing.Literal["_barometric_pressure", b"_barometric_pressure", "_current", b"_current", "_distance", b"_distance", "_gas_resistance", b"_gas_resistance", "_iaq", b"_iaq", "_ir_lux", b"_ir_lux", "_lux", b"_lux", "_radiation", b"_radiation", "_rainfall_1h", b"_rainfall_1h", "_rainfall_24h", b"_rainfall_24h", "_relative_humidity", b"_relative_humidity", "_soil_moisture", b"_soil_moisture", "_soil_temperature", b"_soil_temperature", "_temperature", b"_temperature", "_uv_lux", b"_uv_lux", "_voltage", b"_voltage", "_weight", b"_weight", "_white_lux", b"_white_lux", "_wind_direction", b"_wind_direction", "_wind_gust", b"_wind_gust", "_wind_lull", b"_wind_lull", "_wind_speed", b"_wind_speed", "barometric_pressure", b"barometric_pressure", "current", b"current", "distance", b"distance", "gas_resistance", b"gas_resistance", "iaq", b"iaq", "ir_lux", b"ir_lux", "lux", b"lux", "radiation", b"radiation", "rainfall_1h", b"rainfall_1h", "rainfall_24h", b"rainfall_24h", "relative_humidity", b"relative_humidity", "soil_moisture", b"soil_moisture", "soil_temperature", b"soil_temperature", "temperature", b"temperature", "uv_lux", b"uv_lux", "voltage", b"voltage", "weight", b"weight", "white_lux", b"white_lux", "wind_direction", b"wind_direction", "wind_gust", b"wind_gust", "wind_lull", b"wind_lull", "wind_speed", b"wind_speed"]) -> None: ...
|
||||||
@typing.overload
|
@typing.overload
|
||||||
def WhichOneof(self, oneof_group: typing.Literal["_barometric_pressure", b"_barometric_pressure"]) -> typing.Literal["barometric_pressure"] | None: ...
|
def WhichOneof(self, oneof_group: typing.Literal["_barometric_pressure", b"_barometric_pressure"]) -> typing.Literal["barometric_pressure"] | None: ...
|
||||||
@typing.overload
|
@typing.overload
|
||||||
@@ -461,8 +611,18 @@ class EnvironmentMetrics(google.protobuf.message.Message):
|
|||||||
@typing.overload
|
@typing.overload
|
||||||
def WhichOneof(self, oneof_group: typing.Literal["_lux", b"_lux"]) -> typing.Literal["lux"] | None: ...
|
def WhichOneof(self, oneof_group: typing.Literal["_lux", b"_lux"]) -> typing.Literal["lux"] | None: ...
|
||||||
@typing.overload
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_radiation", b"_radiation"]) -> typing.Literal["radiation"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_rainfall_1h", b"_rainfall_1h"]) -> typing.Literal["rainfall_1h"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_rainfall_24h", b"_rainfall_24h"]) -> typing.Literal["rainfall_24h"] | None: ...
|
||||||
|
@typing.overload
|
||||||
def WhichOneof(self, oneof_group: typing.Literal["_relative_humidity", b"_relative_humidity"]) -> typing.Literal["relative_humidity"] | None: ...
|
def WhichOneof(self, oneof_group: typing.Literal["_relative_humidity", b"_relative_humidity"]) -> typing.Literal["relative_humidity"] | None: ...
|
||||||
@typing.overload
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_soil_moisture", b"_soil_moisture"]) -> typing.Literal["soil_moisture"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_soil_temperature", b"_soil_temperature"]) -> typing.Literal["soil_temperature"] | None: ...
|
||||||
|
@typing.overload
|
||||||
def WhichOneof(self, oneof_group: typing.Literal["_temperature", b"_temperature"]) -> typing.Literal["temperature"] | None: ...
|
def WhichOneof(self, oneof_group: typing.Literal["_temperature", b"_temperature"]) -> typing.Literal["temperature"] | None: ...
|
||||||
@typing.overload
|
@typing.overload
|
||||||
def WhichOneof(self, oneof_group: typing.Literal["_uv_lux", b"_uv_lux"]) -> typing.Literal["uv_lux"] | None: ...
|
def WhichOneof(self, oneof_group: typing.Literal["_uv_lux", b"_uv_lux"]) -> typing.Literal["uv_lux"] | None: ...
|
||||||
@@ -497,6 +657,16 @@ class PowerMetrics(google.protobuf.message.Message):
|
|||||||
CH2_CURRENT_FIELD_NUMBER: builtins.int
|
CH2_CURRENT_FIELD_NUMBER: builtins.int
|
||||||
CH3_VOLTAGE_FIELD_NUMBER: builtins.int
|
CH3_VOLTAGE_FIELD_NUMBER: builtins.int
|
||||||
CH3_CURRENT_FIELD_NUMBER: builtins.int
|
CH3_CURRENT_FIELD_NUMBER: builtins.int
|
||||||
|
CH4_VOLTAGE_FIELD_NUMBER: builtins.int
|
||||||
|
CH4_CURRENT_FIELD_NUMBER: builtins.int
|
||||||
|
CH5_VOLTAGE_FIELD_NUMBER: builtins.int
|
||||||
|
CH5_CURRENT_FIELD_NUMBER: builtins.int
|
||||||
|
CH6_VOLTAGE_FIELD_NUMBER: builtins.int
|
||||||
|
CH6_CURRENT_FIELD_NUMBER: builtins.int
|
||||||
|
CH7_VOLTAGE_FIELD_NUMBER: builtins.int
|
||||||
|
CH7_CURRENT_FIELD_NUMBER: builtins.int
|
||||||
|
CH8_VOLTAGE_FIELD_NUMBER: builtins.int
|
||||||
|
CH8_CURRENT_FIELD_NUMBER: builtins.int
|
||||||
ch1_voltage: builtins.float
|
ch1_voltage: builtins.float
|
||||||
"""
|
"""
|
||||||
Voltage (Ch1)
|
Voltage (Ch1)
|
||||||
@@ -521,6 +691,46 @@ class PowerMetrics(google.protobuf.message.Message):
|
|||||||
"""
|
"""
|
||||||
Current (Ch3)
|
Current (Ch3)
|
||||||
"""
|
"""
|
||||||
|
ch4_voltage: builtins.float
|
||||||
|
"""
|
||||||
|
Voltage (Ch4)
|
||||||
|
"""
|
||||||
|
ch4_current: builtins.float
|
||||||
|
"""
|
||||||
|
Current (Ch4)
|
||||||
|
"""
|
||||||
|
ch5_voltage: builtins.float
|
||||||
|
"""
|
||||||
|
Voltage (Ch5)
|
||||||
|
"""
|
||||||
|
ch5_current: builtins.float
|
||||||
|
"""
|
||||||
|
Current (Ch5)
|
||||||
|
"""
|
||||||
|
ch6_voltage: builtins.float
|
||||||
|
"""
|
||||||
|
Voltage (Ch6)
|
||||||
|
"""
|
||||||
|
ch6_current: builtins.float
|
||||||
|
"""
|
||||||
|
Current (Ch6)
|
||||||
|
"""
|
||||||
|
ch7_voltage: builtins.float
|
||||||
|
"""
|
||||||
|
Voltage (Ch7)
|
||||||
|
"""
|
||||||
|
ch7_current: builtins.float
|
||||||
|
"""
|
||||||
|
Current (Ch7)
|
||||||
|
"""
|
||||||
|
ch8_voltage: builtins.float
|
||||||
|
"""
|
||||||
|
Voltage (Ch8)
|
||||||
|
"""
|
||||||
|
ch8_current: builtins.float
|
||||||
|
"""
|
||||||
|
Current (Ch8)
|
||||||
|
"""
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
@@ -530,9 +740,19 @@ class PowerMetrics(google.protobuf.message.Message):
|
|||||||
ch2_current: builtins.float | None = ...,
|
ch2_current: builtins.float | None = ...,
|
||||||
ch3_voltage: builtins.float | None = ...,
|
ch3_voltage: builtins.float | None = ...,
|
||||||
ch3_current: builtins.float | None = ...,
|
ch3_current: builtins.float | None = ...,
|
||||||
|
ch4_voltage: builtins.float | None = ...,
|
||||||
|
ch4_current: builtins.float | None = ...,
|
||||||
|
ch5_voltage: builtins.float | None = ...,
|
||||||
|
ch5_current: builtins.float | None = ...,
|
||||||
|
ch6_voltage: builtins.float | None = ...,
|
||||||
|
ch6_current: builtins.float | None = ...,
|
||||||
|
ch7_voltage: builtins.float | None = ...,
|
||||||
|
ch7_current: builtins.float | None = ...,
|
||||||
|
ch8_voltage: builtins.float | None = ...,
|
||||||
|
ch8_current: builtins.float | None = ...,
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
def HasField(self, field_name: typing.Literal["_ch1_current", b"_ch1_current", "_ch1_voltage", b"_ch1_voltage", "_ch2_current", b"_ch2_current", "_ch2_voltage", b"_ch2_voltage", "_ch3_current", b"_ch3_current", "_ch3_voltage", b"_ch3_voltage", "ch1_current", b"ch1_current", "ch1_voltage", b"ch1_voltage", "ch2_current", b"ch2_current", "ch2_voltage", b"ch2_voltage", "ch3_current", b"ch3_current", "ch3_voltage", b"ch3_voltage"]) -> builtins.bool: ...
|
def HasField(self, field_name: typing.Literal["_ch1_current", b"_ch1_current", "_ch1_voltage", b"_ch1_voltage", "_ch2_current", b"_ch2_current", "_ch2_voltage", b"_ch2_voltage", "_ch3_current", b"_ch3_current", "_ch3_voltage", b"_ch3_voltage", "_ch4_current", b"_ch4_current", "_ch4_voltage", b"_ch4_voltage", "_ch5_current", b"_ch5_current", "_ch5_voltage", b"_ch5_voltage", "_ch6_current", b"_ch6_current", "_ch6_voltage", b"_ch6_voltage", "_ch7_current", b"_ch7_current", "_ch7_voltage", b"_ch7_voltage", "_ch8_current", b"_ch8_current", "_ch8_voltage", b"_ch8_voltage", "ch1_current", b"ch1_current", "ch1_voltage", b"ch1_voltage", "ch2_current", b"ch2_current", "ch2_voltage", b"ch2_voltage", "ch3_current", b"ch3_current", "ch3_voltage", b"ch3_voltage", "ch4_current", b"ch4_current", "ch4_voltage", b"ch4_voltage", "ch5_current", b"ch5_current", "ch5_voltage", b"ch5_voltage", "ch6_current", b"ch6_current", "ch6_voltage", b"ch6_voltage", "ch7_current", b"ch7_current", "ch7_voltage", b"ch7_voltage", "ch8_current", b"ch8_current", "ch8_voltage", b"ch8_voltage"]) -> builtins.bool: ...
|
||||||
def ClearField(self, field_name: typing.Literal["_ch1_current", b"_ch1_current", "_ch1_voltage", b"_ch1_voltage", "_ch2_current", b"_ch2_current", "_ch2_voltage", b"_ch2_voltage", "_ch3_current", b"_ch3_current", "_ch3_voltage", b"_ch3_voltage", "ch1_current", b"ch1_current", "ch1_voltage", b"ch1_voltage", "ch2_current", b"ch2_current", "ch2_voltage", b"ch2_voltage", "ch3_current", b"ch3_current", "ch3_voltage", b"ch3_voltage"]) -> None: ...
|
def ClearField(self, field_name: typing.Literal["_ch1_current", b"_ch1_current", "_ch1_voltage", b"_ch1_voltage", "_ch2_current", b"_ch2_current", "_ch2_voltage", b"_ch2_voltage", "_ch3_current", b"_ch3_current", "_ch3_voltage", b"_ch3_voltage", "_ch4_current", b"_ch4_current", "_ch4_voltage", b"_ch4_voltage", "_ch5_current", b"_ch5_current", "_ch5_voltage", b"_ch5_voltage", "_ch6_current", b"_ch6_current", "_ch6_voltage", b"_ch6_voltage", "_ch7_current", b"_ch7_current", "_ch7_voltage", b"_ch7_voltage", "_ch8_current", b"_ch8_current", "_ch8_voltage", b"_ch8_voltage", "ch1_current", b"ch1_current", "ch1_voltage", b"ch1_voltage", "ch2_current", b"ch2_current", "ch2_voltage", b"ch2_voltage", "ch3_current", b"ch3_current", "ch3_voltage", b"ch3_voltage", "ch4_current", b"ch4_current", "ch4_voltage", b"ch4_voltage", "ch5_current", b"ch5_current", "ch5_voltage", b"ch5_voltage", "ch6_current", b"ch6_current", "ch6_voltage", b"ch6_voltage", "ch7_current", b"ch7_current", "ch7_voltage", b"ch7_voltage", "ch8_current", b"ch8_current", "ch8_voltage", b"ch8_voltage"]) -> None: ...
|
||||||
@typing.overload
|
@typing.overload
|
||||||
def WhichOneof(self, oneof_group: typing.Literal["_ch1_current", b"_ch1_current"]) -> typing.Literal["ch1_current"] | None: ...
|
def WhichOneof(self, oneof_group: typing.Literal["_ch1_current", b"_ch1_current"]) -> typing.Literal["ch1_current"] | None: ...
|
||||||
@typing.overload
|
@typing.overload
|
||||||
@@ -545,6 +765,26 @@ class PowerMetrics(google.protobuf.message.Message):
|
|||||||
def WhichOneof(self, oneof_group: typing.Literal["_ch3_current", b"_ch3_current"]) -> typing.Literal["ch3_current"] | None: ...
|
def WhichOneof(self, oneof_group: typing.Literal["_ch3_current", b"_ch3_current"]) -> typing.Literal["ch3_current"] | None: ...
|
||||||
@typing.overload
|
@typing.overload
|
||||||
def WhichOneof(self, oneof_group: typing.Literal["_ch3_voltage", b"_ch3_voltage"]) -> typing.Literal["ch3_voltage"] | None: ...
|
def WhichOneof(self, oneof_group: typing.Literal["_ch3_voltage", b"_ch3_voltage"]) -> typing.Literal["ch3_voltage"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_ch4_current", b"_ch4_current"]) -> typing.Literal["ch4_current"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_ch4_voltage", b"_ch4_voltage"]) -> typing.Literal["ch4_voltage"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_ch5_current", b"_ch5_current"]) -> typing.Literal["ch5_current"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_ch5_voltage", b"_ch5_voltage"]) -> typing.Literal["ch5_voltage"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_ch6_current", b"_ch6_current"]) -> typing.Literal["ch6_current"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_ch6_voltage", b"_ch6_voltage"]) -> typing.Literal["ch6_voltage"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_ch7_current", b"_ch7_current"]) -> typing.Literal["ch7_current"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_ch7_voltage", b"_ch7_voltage"]) -> typing.Literal["ch7_voltage"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_ch8_current", b"_ch8_current"]) -> typing.Literal["ch8_current"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_ch8_voltage", b"_ch8_voltage"]) -> typing.Literal["ch8_voltage"] | None: ...
|
||||||
|
|
||||||
global___PowerMetrics = PowerMetrics
|
global___PowerMetrics = PowerMetrics
|
||||||
|
|
||||||
@@ -568,53 +808,118 @@ class AirQualityMetrics(google.protobuf.message.Message):
|
|||||||
PARTICLES_25UM_FIELD_NUMBER: builtins.int
|
PARTICLES_25UM_FIELD_NUMBER: builtins.int
|
||||||
PARTICLES_50UM_FIELD_NUMBER: builtins.int
|
PARTICLES_50UM_FIELD_NUMBER: builtins.int
|
||||||
PARTICLES_100UM_FIELD_NUMBER: builtins.int
|
PARTICLES_100UM_FIELD_NUMBER: builtins.int
|
||||||
|
CO2_FIELD_NUMBER: builtins.int
|
||||||
|
CO2_TEMPERATURE_FIELD_NUMBER: builtins.int
|
||||||
|
CO2_HUMIDITY_FIELD_NUMBER: builtins.int
|
||||||
|
FORM_FORMALDEHYDE_FIELD_NUMBER: builtins.int
|
||||||
|
FORM_HUMIDITY_FIELD_NUMBER: builtins.int
|
||||||
|
FORM_TEMPERATURE_FIELD_NUMBER: builtins.int
|
||||||
|
PM40_STANDARD_FIELD_NUMBER: builtins.int
|
||||||
|
PARTICLES_40UM_FIELD_NUMBER: builtins.int
|
||||||
|
PM_TEMPERATURE_FIELD_NUMBER: builtins.int
|
||||||
|
PM_HUMIDITY_FIELD_NUMBER: builtins.int
|
||||||
|
PM_VOC_IDX_FIELD_NUMBER: builtins.int
|
||||||
|
PM_NOX_IDX_FIELD_NUMBER: builtins.int
|
||||||
|
PARTICLES_TPS_FIELD_NUMBER: builtins.int
|
||||||
pm10_standard: builtins.int
|
pm10_standard: builtins.int
|
||||||
"""
|
"""
|
||||||
Concentration Units Standard PM1.0
|
Concentration Units Standard PM1.0 in ug/m3
|
||||||
"""
|
"""
|
||||||
pm25_standard: builtins.int
|
pm25_standard: builtins.int
|
||||||
"""
|
"""
|
||||||
Concentration Units Standard PM2.5
|
Concentration Units Standard PM2.5 in ug/m3
|
||||||
"""
|
"""
|
||||||
pm100_standard: builtins.int
|
pm100_standard: builtins.int
|
||||||
"""
|
"""
|
||||||
Concentration Units Standard PM10.0
|
Concentration Units Standard PM10.0 in ug/m3
|
||||||
"""
|
"""
|
||||||
pm10_environmental: builtins.int
|
pm10_environmental: builtins.int
|
||||||
"""
|
"""
|
||||||
Concentration Units Environmental PM1.0
|
Concentration Units Environmental PM1.0 in ug/m3
|
||||||
"""
|
"""
|
||||||
pm25_environmental: builtins.int
|
pm25_environmental: builtins.int
|
||||||
"""
|
"""
|
||||||
Concentration Units Environmental PM2.5
|
Concentration Units Environmental PM2.5 in ug/m3
|
||||||
"""
|
"""
|
||||||
pm100_environmental: builtins.int
|
pm100_environmental: builtins.int
|
||||||
"""
|
"""
|
||||||
Concentration Units Environmental PM10.0
|
Concentration Units Environmental PM10.0 in ug/m3
|
||||||
"""
|
"""
|
||||||
particles_03um: builtins.int
|
particles_03um: builtins.int
|
||||||
"""
|
"""
|
||||||
0.3um Particle Count
|
0.3um Particle Count in #/0.1l
|
||||||
"""
|
"""
|
||||||
particles_05um: builtins.int
|
particles_05um: builtins.int
|
||||||
"""
|
"""
|
||||||
0.5um Particle Count
|
0.5um Particle Count in #/0.1l
|
||||||
"""
|
"""
|
||||||
particles_10um: builtins.int
|
particles_10um: builtins.int
|
||||||
"""
|
"""
|
||||||
1.0um Particle Count
|
1.0um Particle Count in #/0.1l
|
||||||
"""
|
"""
|
||||||
particles_25um: builtins.int
|
particles_25um: builtins.int
|
||||||
"""
|
"""
|
||||||
2.5um Particle Count
|
2.5um Particle Count in #/0.1l
|
||||||
"""
|
"""
|
||||||
particles_50um: builtins.int
|
particles_50um: builtins.int
|
||||||
"""
|
"""
|
||||||
5.0um Particle Count
|
5.0um Particle Count in #/0.1l
|
||||||
"""
|
"""
|
||||||
particles_100um: builtins.int
|
particles_100um: builtins.int
|
||||||
"""
|
"""
|
||||||
10.0um Particle Count
|
10.0um Particle Count in #/0.1l
|
||||||
|
"""
|
||||||
|
co2: builtins.int
|
||||||
|
"""
|
||||||
|
CO2 concentration in ppm
|
||||||
|
"""
|
||||||
|
co2_temperature: builtins.float
|
||||||
|
"""
|
||||||
|
CO2 sensor temperature in degC
|
||||||
|
"""
|
||||||
|
co2_humidity: builtins.float
|
||||||
|
"""
|
||||||
|
CO2 sensor relative humidity in %
|
||||||
|
"""
|
||||||
|
form_formaldehyde: builtins.float
|
||||||
|
"""
|
||||||
|
Formaldehyde sensor formaldehyde concentration in ppb
|
||||||
|
"""
|
||||||
|
form_humidity: builtins.float
|
||||||
|
"""
|
||||||
|
Formaldehyde sensor relative humidity in %RH
|
||||||
|
"""
|
||||||
|
form_temperature: builtins.float
|
||||||
|
"""
|
||||||
|
Formaldehyde sensor temperature in degrees Celsius
|
||||||
|
"""
|
||||||
|
pm40_standard: builtins.int
|
||||||
|
"""
|
||||||
|
Concentration Units Standard PM4.0 in ug/m3
|
||||||
|
"""
|
||||||
|
particles_40um: builtins.int
|
||||||
|
"""
|
||||||
|
4.0um Particle Count in #/0.1l
|
||||||
|
"""
|
||||||
|
pm_temperature: builtins.float
|
||||||
|
"""
|
||||||
|
PM Sensor Temperature
|
||||||
|
"""
|
||||||
|
pm_humidity: builtins.float
|
||||||
|
"""
|
||||||
|
PM Sensor humidity
|
||||||
|
"""
|
||||||
|
pm_voc_idx: builtins.float
|
||||||
|
"""
|
||||||
|
PM Sensor VOC Index
|
||||||
|
"""
|
||||||
|
pm_nox_idx: builtins.float
|
||||||
|
"""
|
||||||
|
PM Sensor NOx Index
|
||||||
|
"""
|
||||||
|
particles_tps: builtins.float
|
||||||
|
"""
|
||||||
|
Typical Particle Size in um
|
||||||
"""
|
"""
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -631,9 +936,34 @@ class AirQualityMetrics(google.protobuf.message.Message):
|
|||||||
particles_25um: builtins.int | None = ...,
|
particles_25um: builtins.int | None = ...,
|
||||||
particles_50um: builtins.int | None = ...,
|
particles_50um: builtins.int | None = ...,
|
||||||
particles_100um: builtins.int | None = ...,
|
particles_100um: builtins.int | None = ...,
|
||||||
|
co2: builtins.int | None = ...,
|
||||||
|
co2_temperature: builtins.float | None = ...,
|
||||||
|
co2_humidity: builtins.float | None = ...,
|
||||||
|
form_formaldehyde: builtins.float | None = ...,
|
||||||
|
form_humidity: builtins.float | None = ...,
|
||||||
|
form_temperature: builtins.float | None = ...,
|
||||||
|
pm40_standard: builtins.int | None = ...,
|
||||||
|
particles_40um: builtins.int | None = ...,
|
||||||
|
pm_temperature: builtins.float | None = ...,
|
||||||
|
pm_humidity: builtins.float | None = ...,
|
||||||
|
pm_voc_idx: builtins.float | None = ...,
|
||||||
|
pm_nox_idx: builtins.float | None = ...,
|
||||||
|
particles_tps: builtins.float | None = ...,
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
def HasField(self, field_name: typing.Literal["_particles_03um", b"_particles_03um", "_particles_05um", b"_particles_05um", "_particles_100um", b"_particles_100um", "_particles_10um", b"_particles_10um", "_particles_25um", b"_particles_25um", "_particles_50um", b"_particles_50um", "_pm100_environmental", b"_pm100_environmental", "_pm100_standard", b"_pm100_standard", "_pm10_environmental", b"_pm10_environmental", "_pm10_standard", b"_pm10_standard", "_pm25_environmental", b"_pm25_environmental", "_pm25_standard", b"_pm25_standard", "particles_03um", b"particles_03um", "particles_05um", b"particles_05um", "particles_100um", b"particles_100um", "particles_10um", b"particles_10um", "particles_25um", b"particles_25um", "particles_50um", b"particles_50um", "pm100_environmental", b"pm100_environmental", "pm100_standard", b"pm100_standard", "pm10_environmental", b"pm10_environmental", "pm10_standard", b"pm10_standard", "pm25_environmental", b"pm25_environmental", "pm25_standard", b"pm25_standard"]) -> builtins.bool: ...
|
def HasField(self, field_name: typing.Literal["_co2", b"_co2", "_co2_humidity", b"_co2_humidity", "_co2_temperature", b"_co2_temperature", "_form_formaldehyde", b"_form_formaldehyde", "_form_humidity", b"_form_humidity", "_form_temperature", b"_form_temperature", "_particles_03um", b"_particles_03um", "_particles_05um", b"_particles_05um", "_particles_100um", b"_particles_100um", "_particles_10um", b"_particles_10um", "_particles_25um", b"_particles_25um", "_particles_40um", b"_particles_40um", "_particles_50um", b"_particles_50um", "_particles_tps", b"_particles_tps", "_pm100_environmental", b"_pm100_environmental", "_pm100_standard", b"_pm100_standard", "_pm10_environmental", b"_pm10_environmental", "_pm10_standard", b"_pm10_standard", "_pm25_environmental", b"_pm25_environmental", "_pm25_standard", b"_pm25_standard", "_pm40_standard", b"_pm40_standard", "_pm_humidity", b"_pm_humidity", "_pm_nox_idx", b"_pm_nox_idx", "_pm_temperature", b"_pm_temperature", "_pm_voc_idx", b"_pm_voc_idx", "co2", b"co2", "co2_humidity", b"co2_humidity", "co2_temperature", b"co2_temperature", "form_formaldehyde", b"form_formaldehyde", "form_humidity", b"form_humidity", "form_temperature", b"form_temperature", "particles_03um", b"particles_03um", "particles_05um", b"particles_05um", "particles_100um", b"particles_100um", "particles_10um", b"particles_10um", "particles_25um", b"particles_25um", "particles_40um", b"particles_40um", "particles_50um", b"particles_50um", "particles_tps", b"particles_tps", "pm100_environmental", b"pm100_environmental", "pm100_standard", b"pm100_standard", "pm10_environmental", b"pm10_environmental", "pm10_standard", b"pm10_standard", "pm25_environmental", b"pm25_environmental", "pm25_standard", b"pm25_standard", "pm40_standard", b"pm40_standard", "pm_humidity", b"pm_humidity", "pm_nox_idx", b"pm_nox_idx", "pm_temperature", b"pm_temperature", "pm_voc_idx", b"pm_voc_idx"]) -> builtins.bool: ...
|
||||||
def ClearField(self, field_name: typing.Literal["_particles_03um", b"_particles_03um", "_particles_05um", b"_particles_05um", "_particles_100um", b"_particles_100um", "_particles_10um", b"_particles_10um", "_particles_25um", b"_particles_25um", "_particles_50um", b"_particles_50um", "_pm100_environmental", b"_pm100_environmental", "_pm100_standard", b"_pm100_standard", "_pm10_environmental", b"_pm10_environmental", "_pm10_standard", b"_pm10_standard", "_pm25_environmental", b"_pm25_environmental", "_pm25_standard", b"_pm25_standard", "particles_03um", b"particles_03um", "particles_05um", b"particles_05um", "particles_100um", b"particles_100um", "particles_10um", b"particles_10um", "particles_25um", b"particles_25um", "particles_50um", b"particles_50um", "pm100_environmental", b"pm100_environmental", "pm100_standard", b"pm100_standard", "pm10_environmental", b"pm10_environmental", "pm10_standard", b"pm10_standard", "pm25_environmental", b"pm25_environmental", "pm25_standard", b"pm25_standard"]) -> None: ...
|
def ClearField(self, field_name: typing.Literal["_co2", b"_co2", "_co2_humidity", b"_co2_humidity", "_co2_temperature", b"_co2_temperature", "_form_formaldehyde", b"_form_formaldehyde", "_form_humidity", b"_form_humidity", "_form_temperature", b"_form_temperature", "_particles_03um", b"_particles_03um", "_particles_05um", b"_particles_05um", "_particles_100um", b"_particles_100um", "_particles_10um", b"_particles_10um", "_particles_25um", b"_particles_25um", "_particles_40um", b"_particles_40um", "_particles_50um", b"_particles_50um", "_particles_tps", b"_particles_tps", "_pm100_environmental", b"_pm100_environmental", "_pm100_standard", b"_pm100_standard", "_pm10_environmental", b"_pm10_environmental", "_pm10_standard", b"_pm10_standard", "_pm25_environmental", b"_pm25_environmental", "_pm25_standard", b"_pm25_standard", "_pm40_standard", b"_pm40_standard", "_pm_humidity", b"_pm_humidity", "_pm_nox_idx", b"_pm_nox_idx", "_pm_temperature", b"_pm_temperature", "_pm_voc_idx", b"_pm_voc_idx", "co2", b"co2", "co2_humidity", b"co2_humidity", "co2_temperature", b"co2_temperature", "form_formaldehyde", b"form_formaldehyde", "form_humidity", b"form_humidity", "form_temperature", b"form_temperature", "particles_03um", b"particles_03um", "particles_05um", b"particles_05um", "particles_100um", b"particles_100um", "particles_10um", b"particles_10um", "particles_25um", b"particles_25um", "particles_40um", b"particles_40um", "particles_50um", b"particles_50um", "particles_tps", b"particles_tps", "pm100_environmental", b"pm100_environmental", "pm100_standard", b"pm100_standard", "pm10_environmental", b"pm10_environmental", "pm10_standard", b"pm10_standard", "pm25_environmental", b"pm25_environmental", "pm25_standard", b"pm25_standard", "pm40_standard", b"pm40_standard", "pm_humidity", b"pm_humidity", "pm_nox_idx", b"pm_nox_idx", "pm_temperature", b"pm_temperature", "pm_voc_idx", b"pm_voc_idx"]) -> None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_co2", b"_co2"]) -> typing.Literal["co2"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_co2_humidity", b"_co2_humidity"]) -> typing.Literal["co2_humidity"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_co2_temperature", b"_co2_temperature"]) -> typing.Literal["co2_temperature"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_form_formaldehyde", b"_form_formaldehyde"]) -> typing.Literal["form_formaldehyde"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_form_humidity", b"_form_humidity"]) -> typing.Literal["form_humidity"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_form_temperature", b"_form_temperature"]) -> typing.Literal["form_temperature"] | None: ...
|
||||||
@typing.overload
|
@typing.overload
|
||||||
def WhichOneof(self, oneof_group: typing.Literal["_particles_03um", b"_particles_03um"]) -> typing.Literal["particles_03um"] | None: ...
|
def WhichOneof(self, oneof_group: typing.Literal["_particles_03um", b"_particles_03um"]) -> typing.Literal["particles_03um"] | None: ...
|
||||||
@typing.overload
|
@typing.overload
|
||||||
@@ -645,8 +975,12 @@ class AirQualityMetrics(google.protobuf.message.Message):
|
|||||||
@typing.overload
|
@typing.overload
|
||||||
def WhichOneof(self, oneof_group: typing.Literal["_particles_25um", b"_particles_25um"]) -> typing.Literal["particles_25um"] | None: ...
|
def WhichOneof(self, oneof_group: typing.Literal["_particles_25um", b"_particles_25um"]) -> typing.Literal["particles_25um"] | None: ...
|
||||||
@typing.overload
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_particles_40um", b"_particles_40um"]) -> typing.Literal["particles_40um"] | None: ...
|
||||||
|
@typing.overload
|
||||||
def WhichOneof(self, oneof_group: typing.Literal["_particles_50um", b"_particles_50um"]) -> typing.Literal["particles_50um"] | None: ...
|
def WhichOneof(self, oneof_group: typing.Literal["_particles_50um", b"_particles_50um"]) -> typing.Literal["particles_50um"] | None: ...
|
||||||
@typing.overload
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_particles_tps", b"_particles_tps"]) -> typing.Literal["particles_tps"] | None: ...
|
||||||
|
@typing.overload
|
||||||
def WhichOneof(self, oneof_group: typing.Literal["_pm100_environmental", b"_pm100_environmental"]) -> typing.Literal["pm100_environmental"] | None: ...
|
def WhichOneof(self, oneof_group: typing.Literal["_pm100_environmental", b"_pm100_environmental"]) -> typing.Literal["pm100_environmental"] | None: ...
|
||||||
@typing.overload
|
@typing.overload
|
||||||
def WhichOneof(self, oneof_group: typing.Literal["_pm100_standard", b"_pm100_standard"]) -> typing.Literal["pm100_standard"] | None: ...
|
def WhichOneof(self, oneof_group: typing.Literal["_pm100_standard", b"_pm100_standard"]) -> typing.Literal["pm100_standard"] | None: ...
|
||||||
@@ -658,6 +992,16 @@ class AirQualityMetrics(google.protobuf.message.Message):
|
|||||||
def WhichOneof(self, oneof_group: typing.Literal["_pm25_environmental", b"_pm25_environmental"]) -> typing.Literal["pm25_environmental"] | None: ...
|
def WhichOneof(self, oneof_group: typing.Literal["_pm25_environmental", b"_pm25_environmental"]) -> typing.Literal["pm25_environmental"] | None: ...
|
||||||
@typing.overload
|
@typing.overload
|
||||||
def WhichOneof(self, oneof_group: typing.Literal["_pm25_standard", b"_pm25_standard"]) -> typing.Literal["pm25_standard"] | None: ...
|
def WhichOneof(self, oneof_group: typing.Literal["_pm25_standard", b"_pm25_standard"]) -> typing.Literal["pm25_standard"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_pm40_standard", b"_pm40_standard"]) -> typing.Literal["pm40_standard"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_pm_humidity", b"_pm_humidity"]) -> typing.Literal["pm_humidity"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_pm_nox_idx", b"_pm_nox_idx"]) -> typing.Literal["pm_nox_idx"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_pm_temperature", b"_pm_temperature"]) -> typing.Literal["pm_temperature"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_pm_voc_idx", b"_pm_voc_idx"]) -> typing.Literal["pm_voc_idx"] | None: ...
|
||||||
|
|
||||||
global___AirQualityMetrics = AirQualityMetrics
|
global___AirQualityMetrics = AirQualityMetrics
|
||||||
|
|
||||||
@@ -677,6 +1021,11 @@ class LocalStats(google.protobuf.message.Message):
|
|||||||
NUM_PACKETS_RX_BAD_FIELD_NUMBER: builtins.int
|
NUM_PACKETS_RX_BAD_FIELD_NUMBER: builtins.int
|
||||||
NUM_ONLINE_NODES_FIELD_NUMBER: builtins.int
|
NUM_ONLINE_NODES_FIELD_NUMBER: builtins.int
|
||||||
NUM_TOTAL_NODES_FIELD_NUMBER: builtins.int
|
NUM_TOTAL_NODES_FIELD_NUMBER: builtins.int
|
||||||
|
NUM_RX_DUPE_FIELD_NUMBER: builtins.int
|
||||||
|
NUM_TX_RELAY_FIELD_NUMBER: builtins.int
|
||||||
|
NUM_TX_RELAY_CANCELED_FIELD_NUMBER: builtins.int
|
||||||
|
HEAP_TOTAL_BYTES_FIELD_NUMBER: builtins.int
|
||||||
|
HEAP_FREE_BYTES_FIELD_NUMBER: builtins.int
|
||||||
uptime_seconds: builtins.int
|
uptime_seconds: builtins.int
|
||||||
"""
|
"""
|
||||||
How long the device has been running since the last reboot (in seconds)
|
How long the device has been running since the last reboot (in seconds)
|
||||||
@@ -695,7 +1044,7 @@ class LocalStats(google.protobuf.message.Message):
|
|||||||
"""
|
"""
|
||||||
num_packets_rx: builtins.int
|
num_packets_rx: builtins.int
|
||||||
"""
|
"""
|
||||||
Number of packets received good
|
Number of packets received (both good and bad)
|
||||||
"""
|
"""
|
||||||
num_packets_rx_bad: builtins.int
|
num_packets_rx_bad: builtins.int
|
||||||
"""
|
"""
|
||||||
@@ -709,6 +1058,28 @@ class LocalStats(google.protobuf.message.Message):
|
|||||||
"""
|
"""
|
||||||
Number of nodes total
|
Number of nodes total
|
||||||
"""
|
"""
|
||||||
|
num_rx_dupe: builtins.int
|
||||||
|
"""
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
num_tx_relay: builtins.int
|
||||||
|
"""
|
||||||
|
Number of packets we transmitted that were a relay for others (not originating from ourselves).
|
||||||
|
"""
|
||||||
|
num_tx_relay_canceled: builtins.int
|
||||||
|
"""
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
heap_total_bytes: builtins.int
|
||||||
|
"""
|
||||||
|
Number of bytes used in the heap
|
||||||
|
"""
|
||||||
|
heap_free_bytes: builtins.int
|
||||||
|
"""
|
||||||
|
Number of bytes free in the heap
|
||||||
|
"""
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
@@ -720,11 +1091,135 @@ class LocalStats(google.protobuf.message.Message):
|
|||||||
num_packets_rx_bad: builtins.int = ...,
|
num_packets_rx_bad: builtins.int = ...,
|
||||||
num_online_nodes: builtins.int = ...,
|
num_online_nodes: builtins.int = ...,
|
||||||
num_total_nodes: builtins.int = ...,
|
num_total_nodes: builtins.int = ...,
|
||||||
|
num_rx_dupe: builtins.int = ...,
|
||||||
|
num_tx_relay: builtins.int = ...,
|
||||||
|
num_tx_relay_canceled: builtins.int = ...,
|
||||||
|
heap_total_bytes: builtins.int = ...,
|
||||||
|
heap_free_bytes: builtins.int = ...,
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
def ClearField(self, field_name: typing.Literal["air_util_tx", b"air_util_tx", "channel_utilization", b"channel_utilization", "num_online_nodes", b"num_online_nodes", "num_packets_rx", b"num_packets_rx", "num_packets_rx_bad", b"num_packets_rx_bad", "num_packets_tx", b"num_packets_tx", "num_total_nodes", b"num_total_nodes", "uptime_seconds", b"uptime_seconds"]) -> None: ...
|
def ClearField(self, field_name: typing.Literal["air_util_tx", b"air_util_tx", "channel_utilization", b"channel_utilization", "heap_free_bytes", b"heap_free_bytes", "heap_total_bytes", b"heap_total_bytes", "num_online_nodes", b"num_online_nodes", "num_packets_rx", b"num_packets_rx", "num_packets_rx_bad", b"num_packets_rx_bad", "num_packets_tx", b"num_packets_tx", "num_rx_dupe", b"num_rx_dupe", "num_total_nodes", b"num_total_nodes", "num_tx_relay", b"num_tx_relay", "num_tx_relay_canceled", b"num_tx_relay_canceled", "uptime_seconds", b"uptime_seconds"]) -> None: ...
|
||||||
|
|
||||||
global___LocalStats = LocalStats
|
global___LocalStats = LocalStats
|
||||||
|
|
||||||
|
@typing.final
|
||||||
|
class HealthMetrics(google.protobuf.message.Message):
|
||||||
|
"""
|
||||||
|
Health telemetry metrics
|
||||||
|
"""
|
||||||
|
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||||
|
|
||||||
|
HEART_BPM_FIELD_NUMBER: builtins.int
|
||||||
|
SPO2_FIELD_NUMBER: builtins.int
|
||||||
|
TEMPERATURE_FIELD_NUMBER: builtins.int
|
||||||
|
heart_bpm: builtins.int
|
||||||
|
"""
|
||||||
|
Heart rate (beats per minute)
|
||||||
|
"""
|
||||||
|
spO2: builtins.int
|
||||||
|
"""
|
||||||
|
SpO2 (blood oxygen saturation) level
|
||||||
|
"""
|
||||||
|
temperature: builtins.float
|
||||||
|
"""
|
||||||
|
Body temperature in degrees Celsius
|
||||||
|
"""
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
heart_bpm: builtins.int | None = ...,
|
||||||
|
spO2: builtins.int | None = ...,
|
||||||
|
temperature: builtins.float | None = ...,
|
||||||
|
) -> None: ...
|
||||||
|
def HasField(self, field_name: typing.Literal["_heart_bpm", b"_heart_bpm", "_spO2", b"_spO2", "_temperature", b"_temperature", "heart_bpm", b"heart_bpm", "spO2", b"spO2", "temperature", b"temperature"]) -> builtins.bool: ...
|
||||||
|
def ClearField(self, field_name: typing.Literal["_heart_bpm", b"_heart_bpm", "_spO2", b"_spO2", "_temperature", b"_temperature", "heart_bpm", b"heart_bpm", "spO2", b"spO2", "temperature", b"temperature"]) -> None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_heart_bpm", b"_heart_bpm"]) -> typing.Literal["heart_bpm"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_spO2", b"_spO2"]) -> typing.Literal["spO2"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_temperature", b"_temperature"]) -> typing.Literal["temperature"] | None: ...
|
||||||
|
|
||||||
|
global___HealthMetrics = HealthMetrics
|
||||||
|
|
||||||
|
@typing.final
|
||||||
|
class HostMetrics(google.protobuf.message.Message):
|
||||||
|
"""
|
||||||
|
Linux host metrics
|
||||||
|
"""
|
||||||
|
|
||||||
|
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||||
|
|
||||||
|
UPTIME_SECONDS_FIELD_NUMBER: builtins.int
|
||||||
|
FREEMEM_BYTES_FIELD_NUMBER: builtins.int
|
||||||
|
DISKFREE1_BYTES_FIELD_NUMBER: builtins.int
|
||||||
|
DISKFREE2_BYTES_FIELD_NUMBER: builtins.int
|
||||||
|
DISKFREE3_BYTES_FIELD_NUMBER: builtins.int
|
||||||
|
LOAD1_FIELD_NUMBER: builtins.int
|
||||||
|
LOAD5_FIELD_NUMBER: builtins.int
|
||||||
|
LOAD15_FIELD_NUMBER: builtins.int
|
||||||
|
USER_STRING_FIELD_NUMBER: builtins.int
|
||||||
|
uptime_seconds: builtins.int
|
||||||
|
"""
|
||||||
|
Host system uptime
|
||||||
|
"""
|
||||||
|
freemem_bytes: builtins.int
|
||||||
|
"""
|
||||||
|
Host system free memory
|
||||||
|
"""
|
||||||
|
diskfree1_bytes: builtins.int
|
||||||
|
"""
|
||||||
|
Host system disk space free for /
|
||||||
|
"""
|
||||||
|
diskfree2_bytes: builtins.int
|
||||||
|
"""
|
||||||
|
Secondary system disk space free
|
||||||
|
"""
|
||||||
|
diskfree3_bytes: builtins.int
|
||||||
|
"""
|
||||||
|
Tertiary disk space free
|
||||||
|
"""
|
||||||
|
load1: builtins.int
|
||||||
|
"""
|
||||||
|
Host system one minute load in 1/100ths
|
||||||
|
"""
|
||||||
|
load5: builtins.int
|
||||||
|
"""
|
||||||
|
Host system five minute load in 1/100ths
|
||||||
|
"""
|
||||||
|
load15: builtins.int
|
||||||
|
"""
|
||||||
|
Host system fifteen minute load in 1/100ths
|
||||||
|
"""
|
||||||
|
user_string: builtins.str
|
||||||
|
"""
|
||||||
|
Optional User-provided string for arbitrary host system information
|
||||||
|
that doesn't make sense as a dedicated entry.
|
||||||
|
"""
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
uptime_seconds: builtins.int = ...,
|
||||||
|
freemem_bytes: builtins.int = ...,
|
||||||
|
diskfree1_bytes: builtins.int = ...,
|
||||||
|
diskfree2_bytes: builtins.int | None = ...,
|
||||||
|
diskfree3_bytes: builtins.int | None = ...,
|
||||||
|
load1: builtins.int = ...,
|
||||||
|
load5: builtins.int = ...,
|
||||||
|
load15: builtins.int = ...,
|
||||||
|
user_string: builtins.str | None = ...,
|
||||||
|
) -> None: ...
|
||||||
|
def HasField(self, field_name: typing.Literal["_diskfree2_bytes", b"_diskfree2_bytes", "_diskfree3_bytes", b"_diskfree3_bytes", "_user_string", b"_user_string", "diskfree2_bytes", b"diskfree2_bytes", "diskfree3_bytes", b"diskfree3_bytes", "user_string", b"user_string"]) -> builtins.bool: ...
|
||||||
|
def ClearField(self, field_name: typing.Literal["_diskfree2_bytes", b"_diskfree2_bytes", "_diskfree3_bytes", b"_diskfree3_bytes", "_user_string", b"_user_string", "diskfree1_bytes", b"diskfree1_bytes", "diskfree2_bytes", b"diskfree2_bytes", "diskfree3_bytes", b"diskfree3_bytes", "freemem_bytes", b"freemem_bytes", "load1", b"load1", "load15", b"load15", "load5", b"load5", "uptime_seconds", b"uptime_seconds", "user_string", b"user_string"]) -> None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_diskfree2_bytes", b"_diskfree2_bytes"]) -> typing.Literal["diskfree2_bytes"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_diskfree3_bytes", b"_diskfree3_bytes"]) -> typing.Literal["diskfree3_bytes"] | None: ...
|
||||||
|
@typing.overload
|
||||||
|
def WhichOneof(self, oneof_group: typing.Literal["_user_string", b"_user_string"]) -> typing.Literal["user_string"] | None: ...
|
||||||
|
|
||||||
|
global___HostMetrics = HostMetrics
|
||||||
|
|
||||||
@typing.final
|
@typing.final
|
||||||
class Telemetry(google.protobuf.message.Message):
|
class Telemetry(google.protobuf.message.Message):
|
||||||
"""
|
"""
|
||||||
@@ -739,6 +1234,8 @@ class Telemetry(google.protobuf.message.Message):
|
|||||||
AIR_QUALITY_METRICS_FIELD_NUMBER: builtins.int
|
AIR_QUALITY_METRICS_FIELD_NUMBER: builtins.int
|
||||||
POWER_METRICS_FIELD_NUMBER: builtins.int
|
POWER_METRICS_FIELD_NUMBER: builtins.int
|
||||||
LOCAL_STATS_FIELD_NUMBER: builtins.int
|
LOCAL_STATS_FIELD_NUMBER: builtins.int
|
||||||
|
HEALTH_METRICS_FIELD_NUMBER: builtins.int
|
||||||
|
HOST_METRICS_FIELD_NUMBER: builtins.int
|
||||||
time: builtins.int
|
time: builtins.int
|
||||||
"""
|
"""
|
||||||
Seconds since 1970 - or 0 for unknown/unset
|
Seconds since 1970 - or 0 for unknown/unset
|
||||||
@@ -773,6 +1270,18 @@ class Telemetry(google.protobuf.message.Message):
|
|||||||
Local device mesh statistics
|
Local device mesh statistics
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def health_metrics(self) -> global___HealthMetrics:
|
||||||
|
"""
|
||||||
|
Health telemetry metrics
|
||||||
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def host_metrics(self) -> global___HostMetrics:
|
||||||
|
"""
|
||||||
|
Linux host metrics
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
@@ -782,10 +1291,12 @@ class Telemetry(google.protobuf.message.Message):
|
|||||||
air_quality_metrics: global___AirQualityMetrics | None = ...,
|
air_quality_metrics: global___AirQualityMetrics | None = ...,
|
||||||
power_metrics: global___PowerMetrics | None = ...,
|
power_metrics: global___PowerMetrics | None = ...,
|
||||||
local_stats: global___LocalStats | None = ...,
|
local_stats: global___LocalStats | None = ...,
|
||||||
|
health_metrics: global___HealthMetrics | None = ...,
|
||||||
|
host_metrics: global___HostMetrics | None = ...,
|
||||||
) -> None: ...
|
) -> None: ...
|
||||||
def HasField(self, field_name: typing.Literal["air_quality_metrics", b"air_quality_metrics", "device_metrics", b"device_metrics", "environment_metrics", b"environment_metrics", "local_stats", b"local_stats", "power_metrics", b"power_metrics", "variant", b"variant"]) -> builtins.bool: ...
|
def HasField(self, field_name: typing.Literal["air_quality_metrics", b"air_quality_metrics", "device_metrics", b"device_metrics", "environment_metrics", b"environment_metrics", "health_metrics", b"health_metrics", "host_metrics", b"host_metrics", "local_stats", b"local_stats", "power_metrics", b"power_metrics", "variant", b"variant"]) -> builtins.bool: ...
|
||||||
def ClearField(self, field_name: typing.Literal["air_quality_metrics", b"air_quality_metrics", "device_metrics", b"device_metrics", "environment_metrics", b"environment_metrics", "local_stats", b"local_stats", "power_metrics", b"power_metrics", "time", b"time", "variant", b"variant"]) -> None: ...
|
def ClearField(self, field_name: typing.Literal["air_quality_metrics", b"air_quality_metrics", "device_metrics", b"device_metrics", "environment_metrics", b"environment_metrics", "health_metrics", b"health_metrics", "host_metrics", b"host_metrics", "local_stats", b"local_stats", "power_metrics", b"power_metrics", "time", b"time", "variant", b"variant"]) -> None: ...
|
||||||
def WhichOneof(self, oneof_group: typing.Literal["variant", b"variant"]) -> typing.Literal["device_metrics", "environment_metrics", "air_quality_metrics", "power_metrics", "local_stats"] | None: ...
|
def WhichOneof(self, oneof_group: typing.Literal["variant", b"variant"]) -> typing.Literal["device_metrics", "environment_metrics", "air_quality_metrics", "power_metrics", "local_stats", "health_metrics", "host_metrics"] | None: ...
|
||||||
|
|
||||||
global___Telemetry = Telemetry
|
global___Telemetry = Telemetry
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from meshtastic.protobuf import portnums_pb2, remote_hardware_pb2
|
|||||||
from meshtastic.util import our_exit
|
from meshtastic.util import our_exit
|
||||||
|
|
||||||
|
|
||||||
def onGPIOreceive(packet, interface):
|
def onGPIOreceive(packet, interface) -> None:
|
||||||
"""Callback for received GPIO responses"""
|
"""Callback for received GPIO responses"""
|
||||||
logging.debug(f"packet:{packet} interface:{interface}")
|
logging.debug(f"packet:{packet} interface:{interface}")
|
||||||
gpioValue = 0
|
gpioValue = 0
|
||||||
@@ -37,7 +37,7 @@ class RemoteHardwareClient:
|
|||||||
code for how you can connect to your own custom meshtastic services
|
code for how you can connect to your own custom meshtastic services
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, iface):
|
def __init__(self, iface) -> None:
|
||||||
"""
|
"""
|
||||||
Constructor
|
Constructor
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import logging
|
|||||||
import platform
|
import platform
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from typing import Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
import serial # type: ignore[import-untyped]
|
import serial # type: ignore[import-untyped]
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ if platform.system() != "Windows":
|
|||||||
class SerialInterface(StreamInterface):
|
class SerialInterface(StreamInterface):
|
||||||
"""Interface class for meshtastic devices over a serial link"""
|
"""Interface class for meshtastic devices over a serial link"""
|
||||||
|
|
||||||
def __init__(self, devPath: Optional[str]=None, debugOut=None, noProto=False, connectNow=True, noNodes: bool=False):
|
def __init__(self, devPath: Optional[str]=None, debugOut=None, noProto: bool=False, connectNow: bool=True, noNodes: bool=False) -> None:
|
||||||
"""Constructor, opens a connection to a specified serial port, or if unspecified try to
|
"""Constructor, opens a connection to a specified serial port, or if unspecified try to
|
||||||
find one Meshtastic device by probing
|
find one Meshtastic device by probing
|
||||||
|
|
||||||
@@ -32,13 +32,13 @@ class SerialInterface(StreamInterface):
|
|||||||
self.devPath: Optional[str] = devPath
|
self.devPath: Optional[str] = devPath
|
||||||
|
|
||||||
if self.devPath is None:
|
if self.devPath is None:
|
||||||
ports = meshtastic.util.findPorts(True)
|
ports: List[str] = meshtastic.util.findPorts(True)
|
||||||
logging.debug(f"ports:{ports}")
|
logging.debug(f"ports:{ports}")
|
||||||
if len(ports) == 0:
|
if len(ports) == 0:
|
||||||
print("No Serial Meshtastic device detected, attempting TCP connection on localhost.")
|
print("No Serial Meshtastic device detected, attempting TCP connection on localhost.")
|
||||||
return
|
return
|
||||||
elif len(ports) > 1:
|
elif len(ports) > 1:
|
||||||
message = "Warning: Multiple serial ports were detected so one serial port must be specified with the '--port'.\n"
|
message: str = "Warning: Multiple serial ports were detected so one serial port must be specified with the '--port'.\n"
|
||||||
message += f" Ports detected:{ports}"
|
message += f" Ports detected:{ports}"
|
||||||
meshtastic.util.our_exit(message)
|
meshtastic.util.our_exit(message)
|
||||||
else:
|
else:
|
||||||
@@ -59,14 +59,25 @@ class SerialInterface(StreamInterface):
|
|||||||
self.stream = serial.Serial(
|
self.stream = serial.Serial(
|
||||||
self.devPath, 115200, exclusive=True, timeout=0.5, write_timeout=0
|
self.devPath, 115200, exclusive=True, timeout=0.5, write_timeout=0
|
||||||
)
|
)
|
||||||
self.stream.flush()
|
self.stream.flush() # type: ignore[attr-defined]
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|
||||||
StreamInterface.__init__(
|
StreamInterface.__init__(
|
||||||
self, debugOut=debugOut, noProto=noProto, connectNow=connectNow, noNodes=noNodes
|
self, debugOut=debugOut, noProto=noProto, connectNow=connectNow, noNodes=noNodes
|
||||||
)
|
)
|
||||||
|
|
||||||
def close(self):
|
def __repr__(self):
|
||||||
|
rep = f"SerialInterface(devPath={self.devPath!r}"
|
||||||
|
if hasattr(self, 'debugOut') and self.debugOut is not None:
|
||||||
|
rep += f", debugOut={self.debugOut!r}"
|
||||||
|
if self.noProto:
|
||||||
|
rep += ", noProto=True"
|
||||||
|
if hasattr(self, 'noNodes') and self.noNodes:
|
||||||
|
rep += ", noNodes=True"
|
||||||
|
rep += ")"
|
||||||
|
return rep
|
||||||
|
|
||||||
|
def close(self) -> None:
|
||||||
"""Close a connection to the device"""
|
"""Close a connection to the device"""
|
||||||
if self.stream: # Stream can be null if we were already closed
|
if self.stream: # Stream can be null if we were already closed
|
||||||
self.stream.flush() # FIXME: why are there these two flushes with 100ms sleeps? This shouldn't be necessary
|
self.stream.flush() # FIXME: why are there these two flushes with 100ms sleeps? This shouldn't be necessary
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
"""Stream Interface base class
|
"""Stream Interface base class
|
||||||
"""
|
"""
|
||||||
|
import io
|
||||||
import logging
|
import logging
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
from typing import Optional, cast
|
||||||
|
|
||||||
import serial # type: ignore[import-untyped]
|
import serial # type: ignore[import-untyped]
|
||||||
|
|
||||||
from meshtastic.mesh_interface import MeshInterface
|
from meshtastic.mesh_interface import MeshInterface
|
||||||
@@ -19,7 +22,7 @@ MAX_TO_FROM_RADIO_SIZE = 512
|
|||||||
class StreamInterface(MeshInterface):
|
class StreamInterface(MeshInterface):
|
||||||
"""Interface class for meshtastic devices over a stream link (serial, TCP, etc)"""
|
"""Interface class for meshtastic devices over a stream link (serial, TCP, etc)"""
|
||||||
|
|
||||||
def __init__(self, debugOut=None, noProto=False, connectNow=True, noNodes=False):
|
def __init__(self, debugOut: Optional[io.TextIOWrapper]=None, noProto: bool=False, connectNow: bool=True, noNodes: bool=False) -> None:
|
||||||
"""Constructor, opens a connection to self.stream
|
"""Constructor, opens a connection to self.stream
|
||||||
|
|
||||||
Keyword Arguments:
|
Keyword Arguments:
|
||||||
@@ -35,6 +38,7 @@ class StreamInterface(MeshInterface):
|
|||||||
raise Exception( # pylint: disable=W0719
|
raise Exception( # pylint: disable=W0719
|
||||||
"StreamInterface is now abstract (to update existing code create SerialInterface instead)"
|
"StreamInterface is now abstract (to update existing code create SerialInterface instead)"
|
||||||
)
|
)
|
||||||
|
self.stream: Optional[serial.Serial] # only serial uses this, TCPInterface overrides the relevant methods instead
|
||||||
self._rxBuf = bytes() # empty
|
self._rxBuf = bytes() # empty
|
||||||
self._wantExit = False
|
self._wantExit = False
|
||||||
|
|
||||||
@@ -52,7 +56,7 @@ class StreamInterface(MeshInterface):
|
|||||||
if not noProto:
|
if not noProto:
|
||||||
self.waitForConfig()
|
self.waitForConfig()
|
||||||
|
|
||||||
def connect(self):
|
def connect(self) -> None:
|
||||||
"""Connect to our radio
|
"""Connect to our radio
|
||||||
|
|
||||||
Normally this is called automatically by the constructor, but if you
|
Normally this is called automatically by the constructor, but if you
|
||||||
@@ -63,7 +67,7 @@ class StreamInterface(MeshInterface):
|
|||||||
# if the reading statemachine was parsing a bad packet make sure
|
# if the reading statemachine was parsing a bad packet make sure
|
||||||
# we write enough start bytes to force it to resync (we don't use START1
|
# we write enough start bytes to force it to resync (we don't use START1
|
||||||
# because we want to ensure it is looking for START1)
|
# because we want to ensure it is looking for START1)
|
||||||
p = bytearray([START2] * 32)
|
p: bytes = bytearray([START2] * 32)
|
||||||
self._writeBytes(p)
|
self._writeBytes(p)
|
||||||
time.sleep(0.1) # wait 100ms to give device time to start running
|
time.sleep(0.1) # wait 100ms to give device time to start running
|
||||||
|
|
||||||
@@ -74,7 +78,7 @@ class StreamInterface(MeshInterface):
|
|||||||
if not self.noProto: # Wait for the db download if using the protocol
|
if not self.noProto: # Wait for the db download if using the protocol
|
||||||
self._waitConnected()
|
self._waitConnected()
|
||||||
|
|
||||||
def _disconnected(self):
|
def _disconnected(self) -> None:
|
||||||
"""We override the superclass implementation to close our port"""
|
"""We override the superclass implementation to close our port"""
|
||||||
MeshInterface._disconnected(self)
|
MeshInterface._disconnected(self)
|
||||||
|
|
||||||
@@ -86,7 +90,7 @@ class StreamInterface(MeshInterface):
|
|||||||
# pylint: disable=W0201
|
# pylint: disable=W0201
|
||||||
self.stream = None
|
self.stream = None
|
||||||
|
|
||||||
def _writeBytes(self, b):
|
def _writeBytes(self, b: bytes) -> None:
|
||||||
"""Write an array of bytes to our stream and flush"""
|
"""Write an array of bytes to our stream and flush"""
|
||||||
if self.stream: # ignore writes when stream is closed
|
if self.stream: # ignore writes when stream is closed
|
||||||
self.stream.write(b)
|
self.stream.write(b)
|
||||||
@@ -98,24 +102,24 @@ class StreamInterface(MeshInterface):
|
|||||||
# we sleep here to give the TBeam a chance to work
|
# we sleep here to give the TBeam a chance to work
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|
||||||
def _readBytes(self, length):
|
def _readBytes(self, length) -> Optional[bytes]:
|
||||||
"""Read an array of bytes from our stream"""
|
"""Read an array of bytes from our stream"""
|
||||||
if self.stream:
|
if self.stream:
|
||||||
return self.stream.read(length)
|
return self.stream.read(length)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _sendToRadioImpl(self, toRadio):
|
def _sendToRadioImpl(self, toRadio) -> None:
|
||||||
"""Send a ToRadio protobuf to the device"""
|
"""Send a ToRadio protobuf to the device"""
|
||||||
logging.debug(f"Sending: {stripnl(toRadio)}")
|
logging.debug(f"Sending: {stripnl(toRadio)}")
|
||||||
b = toRadio.SerializeToString()
|
b: bytes = toRadio.SerializeToString()
|
||||||
bufLen = len(b)
|
bufLen: int = len(b)
|
||||||
# We convert into a string, because the TCP code doesn't work with byte arrays
|
# We convert into a string, because the TCP code doesn't work with byte arrays
|
||||||
header = bytes([START1, START2, (bufLen >> 8) & 0xFF, bufLen & 0xFF])
|
header: bytes = bytes([START1, START2, (bufLen >> 8) & 0xFF, bufLen & 0xFF])
|
||||||
logging.debug(f"sending header:{header} b:{b}")
|
logging.debug(f"sending header:{header!r} b:{b!r}")
|
||||||
self._writeBytes(header + b)
|
self._writeBytes(header + b)
|
||||||
|
|
||||||
def close(self):
|
def close(self) -> None:
|
||||||
"""Close a connection to the device"""
|
"""Close a connection to the device"""
|
||||||
logging.debug("Closing stream")
|
logging.debug("Closing stream")
|
||||||
MeshInterface.close(self)
|
MeshInterface.close(self)
|
||||||
@@ -142,7 +146,7 @@ class StreamInterface(MeshInterface):
|
|||||||
else:
|
else:
|
||||||
self.cur_log_line += utf
|
self.cur_log_line += utf
|
||||||
|
|
||||||
def __reader(self):
|
def __reader(self) -> None:
|
||||||
"""The reader thread that reads bytes from our stream"""
|
"""The reader thread that reads bytes from our stream"""
|
||||||
logging.debug("in __reader()")
|
logging.debug("in __reader()")
|
||||||
empty = bytes()
|
empty = bytes()
|
||||||
@@ -150,13 +154,13 @@ class StreamInterface(MeshInterface):
|
|||||||
try:
|
try:
|
||||||
while not self._wantExit:
|
while not self._wantExit:
|
||||||
# logging.debug("reading character")
|
# logging.debug("reading character")
|
||||||
b = self._readBytes(1)
|
b: Optional[bytes] = self._readBytes(1)
|
||||||
# logging.debug("In reader loop")
|
# logging.debug("In reader loop")
|
||||||
# logging.debug(f"read returned {b}")
|
# logging.debug(f"read returned {b}")
|
||||||
if len(b) > 0:
|
if b is not None and len(cast(bytes, b)) > 0:
|
||||||
c = b[0]
|
c: int = b[0]
|
||||||
# logging.debug(f'c:{c}')
|
# logging.debug(f'c:{c}')
|
||||||
ptr = len(self._rxBuf)
|
ptr: int = len(self._rxBuf)
|
||||||
|
|
||||||
# Assume we want to append this byte, fixme use bytearray instead
|
# Assume we want to append this byte, fixme use bytearray instead
|
||||||
self._rxBuf = self._rxBuf + b
|
self._rxBuf = self._rxBuf + b
|
||||||
|
|||||||
@@ -207,6 +207,18 @@ nano_g1 = SupportedDevice(
|
|||||||
usb_product_id_in_hex="55d4",
|
usb_product_id_in_hex="55d4",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
seeed_xiao_s3 = SupportedDevice(
|
||||||
|
name = "Seeed Xiao ESP32-S3",
|
||||||
|
version = "",
|
||||||
|
for_firmware="seeed-xiao-esp32s3",
|
||||||
|
baseport_on_linux="ttyACM",
|
||||||
|
baseport_on_mac="cu.usbmodem",
|
||||||
|
usb_vendor_id_in_hex="2886",
|
||||||
|
usb_product_id_in_hex="0059",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
supported_devices = [
|
supported_devices = [
|
||||||
tbeam_v0_7,
|
tbeam_v0_7,
|
||||||
tbeam_v1_1,
|
tbeam_v1_1,
|
||||||
@@ -226,4 +238,5 @@ supported_devices = [
|
|||||||
rak4631_19003,
|
rak4631_19003,
|
||||||
rak11200,
|
rak11200,
|
||||||
nano_g1,
|
nano_g1,
|
||||||
|
seeed_xiao_s3,
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
"""TCPInterface class for interfacing with http endpoint
|
"""TCPInterface class for interfacing with http endpoint
|
||||||
"""
|
"""
|
||||||
# pylint: disable=R0917
|
# pylint: disable=R0917
|
||||||
|
import contextlib
|
||||||
import logging
|
import logging
|
||||||
import socket
|
import socket
|
||||||
|
import time
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from meshtastic.stream_interface import StreamInterface
|
from meshtastic.stream_interface import StreamInterface
|
||||||
@@ -16,9 +18,9 @@ class TCPInterface(StreamInterface):
|
|||||||
self,
|
self,
|
||||||
hostname: str,
|
hostname: str,
|
||||||
debugOut=None,
|
debugOut=None,
|
||||||
noProto=False,
|
noProto: bool=False,
|
||||||
connectNow=True,
|
connectNow: bool=True,
|
||||||
portNumber=DEFAULT_TCP_PORT,
|
portNumber: int=DEFAULT_TCP_PORT,
|
||||||
noNodes:bool=False,
|
noNodes:bool=False,
|
||||||
):
|
):
|
||||||
"""Constructor, opens a connection to a specified IP address/hostname
|
"""Constructor, opens a connection to a specified IP address/hostname
|
||||||
@@ -29,51 +31,84 @@ class TCPInterface(StreamInterface):
|
|||||||
|
|
||||||
self.stream = None
|
self.stream = None
|
||||||
|
|
||||||
self.hostname = hostname
|
self.hostname: str = hostname
|
||||||
self.portNumber = portNumber
|
self.portNumber: int = portNumber
|
||||||
|
|
||||||
|
self.socket: Optional[socket.socket] = None
|
||||||
|
|
||||||
if connectNow:
|
if connectNow:
|
||||||
logging.debug(f"Connecting to {hostname}") # type: ignore[str-bytes-safe]
|
self.myConnect()
|
||||||
server_address = (hostname, portNumber)
|
|
||||||
sock = socket.create_connection(server_address)
|
|
||||||
self.socket: Optional[socket.socket] = sock
|
|
||||||
else:
|
else:
|
||||||
self.socket = None
|
self.socket = None
|
||||||
|
|
||||||
StreamInterface.__init__(
|
super().__init__(debugOut=debugOut, noProto=noProto, connectNow=connectNow, noNodes=noNodes)
|
||||||
self, debugOut=debugOut, noProto=noProto, connectNow=connectNow, noNodes=noNodes
|
|
||||||
)
|
|
||||||
|
|
||||||
def _socket_shutdown(self):
|
def __repr__(self):
|
||||||
|
rep = f"TCPInterface({self.hostname!r}"
|
||||||
|
if self.debugOut is not None:
|
||||||
|
rep += f", debugOut={self.debugOut!r}"
|
||||||
|
if self.noProto:
|
||||||
|
rep += ", noProto=True"
|
||||||
|
if self.socket is None:
|
||||||
|
rep += ", connectNow=False"
|
||||||
|
if self.portNumber != DEFAULT_TCP_PORT:
|
||||||
|
rep += f", portNumber={self.portNumber!r}"
|
||||||
|
if self.noNodes:
|
||||||
|
rep += ", noNodes=True"
|
||||||
|
rep += ")"
|
||||||
|
return rep
|
||||||
|
|
||||||
|
def _socket_shutdown(self) -> None:
|
||||||
"""Shutdown the socket.
|
"""Shutdown the socket.
|
||||||
Note: Broke out this line so the exception could be unit tested.
|
Note: Broke out this line so the exception could be unit tested.
|
||||||
"""
|
"""
|
||||||
self.socket.shutdown(socket.SHUT_RDWR)
|
if self.socket is not None:
|
||||||
|
self.socket.shutdown(socket.SHUT_RDWR)
|
||||||
|
|
||||||
def myConnect(self):
|
def myConnect(self) -> None:
|
||||||
"""Connect to socket"""
|
"""Connect to socket"""
|
||||||
|
logging.debug(f"Connecting to {self.hostname}") # type: ignore[str-bytes-safe]
|
||||||
server_address = (self.hostname, self.portNumber)
|
server_address = (self.hostname, self.portNumber)
|
||||||
sock = socket.create_connection(server_address)
|
self.socket = socket.create_connection(server_address)
|
||||||
self.socket = sock
|
|
||||||
|
|
||||||
def close(self):
|
def close(self) -> None:
|
||||||
"""Close a connection to the device"""
|
"""Close a connection to the device"""
|
||||||
logging.debug("Closing TCP stream")
|
logging.debug("Closing TCP stream")
|
||||||
StreamInterface.close(self)
|
super().close()
|
||||||
# Sometimes the socket read might be blocked in the reader thread.
|
# Sometimes the socket read might be blocked in the reader thread.
|
||||||
# Therefore we force the shutdown by closing the socket here
|
# Therefore we force the shutdown by closing the socket here
|
||||||
self._wantExit = True
|
self._wantExit = True
|
||||||
if not self.socket is None:
|
if self.socket is not None:
|
||||||
try:
|
with contextlib.suppress(Exception): # Ignore errors in shutdown, because we might have a race with the server
|
||||||
self._socket_shutdown()
|
self._socket_shutdown()
|
||||||
except:
|
|
||||||
pass # Ignore errors in shutdown, because we might have a race with the server
|
|
||||||
self.socket.close()
|
self.socket.close()
|
||||||
|
|
||||||
def _writeBytes(self, b):
|
self.socket = None
|
||||||
"""Write an array of bytes to our stream and flush"""
|
|
||||||
self.socket.send(b)
|
|
||||||
|
|
||||||
def _readBytes(self, length):
|
def _writeBytes(self, b: bytes) -> None:
|
||||||
|
"""Write an array of bytes to our stream and flush"""
|
||||||
|
if self.socket is not None:
|
||||||
|
self.socket.send(b)
|
||||||
|
|
||||||
|
def _readBytes(self, length) -> Optional[bytes]:
|
||||||
"""Read an array of bytes from our stream"""
|
"""Read an array of bytes from our stream"""
|
||||||
return self.socket.recv(length)
|
if self.socket is not None:
|
||||||
|
data = self.socket.recv(length)
|
||||||
|
# empty byte indicates a disconnected socket,
|
||||||
|
# we need to handle it to avoid an infinite loop reading from null socket
|
||||||
|
if data == b'':
|
||||||
|
logging.debug("dead socket, re-connecting")
|
||||||
|
# cleanup and reconnect socket without breaking reader thread
|
||||||
|
with contextlib.suppress(Exception):
|
||||||
|
self._socket_shutdown()
|
||||||
|
self.socket.close()
|
||||||
|
self.socket = None
|
||||||
|
time.sleep(1)
|
||||||
|
self.myConnect()
|
||||||
|
self._startConfig()
|
||||||
|
return None
|
||||||
|
return data
|
||||||
|
|
||||||
|
# no socket, break reader thread
|
||||||
|
self._wantExit = True
|
||||||
|
return None
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import logging
|
|||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
import io
|
||||||
|
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
from dotmap import DotMap # type: ignore[import-untyped]
|
from dotmap import DotMap # type: ignore[import-untyped]
|
||||||
from pubsub import pub # type: ignore[import-untyped]
|
from pubsub import pub # type: ignore[import-untyped]
|
||||||
@@ -15,19 +18,19 @@ from meshtastic.serial_interface import SerialInterface
|
|||||||
from meshtastic.tcp_interface import TCPInterface
|
from meshtastic.tcp_interface import TCPInterface
|
||||||
|
|
||||||
"""The interfaces we are using for our tests"""
|
"""The interfaces we are using for our tests"""
|
||||||
interfaces = None
|
interfaces: List = []
|
||||||
|
|
||||||
"""A list of all packets we received while the current test was running"""
|
"""A list of all packets we received while the current test was running"""
|
||||||
receivedPackets = None
|
receivedPackets: Optional[List] = None
|
||||||
|
|
||||||
testsRunning = False
|
testsRunning: bool = False
|
||||||
|
|
||||||
testNumber = 0
|
testNumber: int = 0
|
||||||
|
|
||||||
sendingInterface = None
|
sendingInterface = None
|
||||||
|
|
||||||
|
|
||||||
def onReceive(packet, interface):
|
def onReceive(packet, interface) -> None:
|
||||||
"""Callback invoked when a packet arrives"""
|
"""Callback invoked when a packet arrives"""
|
||||||
if sendingInterface == interface:
|
if sendingInterface == interface:
|
||||||
pass
|
pass
|
||||||
@@ -42,20 +45,20 @@ def onReceive(packet, interface):
|
|||||||
receivedPackets.append(p)
|
receivedPackets.append(p)
|
||||||
|
|
||||||
|
|
||||||
def onNode(node):
|
def onNode(node) -> None:
|
||||||
"""Callback invoked when the node DB changes"""
|
"""Callback invoked when the node DB changes"""
|
||||||
print(f"Node changed: {node}")
|
print(f"Node changed: {node}")
|
||||||
|
|
||||||
|
|
||||||
def subscribe():
|
def subscribe() -> None:
|
||||||
"""Subscribe to the topics the user probably wants to see, prints output to stdout"""
|
"""Subscribe to the topics the user probably wants to see, prints output to stdout"""
|
||||||
|
|
||||||
pub.subscribe(onNode, "meshtastic.node")
|
pub.subscribe(onNode, "meshtastic.node")
|
||||||
|
|
||||||
|
|
||||||
def testSend(
|
def testSend(
|
||||||
fromInterface, toInterface, isBroadcast=False, asBinary=False, wantAck=False
|
fromInterface, toInterface, isBroadcast: bool=False, asBinary: bool=False, wantAck: bool=False
|
||||||
):
|
) -> bool:
|
||||||
"""
|
"""
|
||||||
Sends one test packet between two nodes and then returns success or failure
|
Sends one test packet between two nodes and then returns success or failure
|
||||||
|
|
||||||
@@ -93,16 +96,16 @@ def testSend(
|
|||||||
return False # Failed to send
|
return False # Failed to send
|
||||||
|
|
||||||
|
|
||||||
def runTests(numTests=50, wantAck=False, maxFailures=0):
|
def runTests(numTests: int=50, wantAck: bool=False, maxFailures: int=0) -> bool:
|
||||||
"""Run the tests."""
|
"""Run the tests."""
|
||||||
logging.info(f"Running {numTests} tests with wantAck={wantAck}")
|
logging.info(f"Running {numTests} tests with wantAck={wantAck}")
|
||||||
numFail = 0
|
numFail: int = 0
|
||||||
numSuccess = 0
|
numSuccess: int = 0
|
||||||
for _ in range(numTests):
|
for _ in range(numTests):
|
||||||
# pylint: disable=W0603
|
# pylint: disable=W0603
|
||||||
global testNumber
|
global testNumber
|
||||||
testNumber = testNumber + 1
|
testNumber = testNumber + 1
|
||||||
isBroadcast = True
|
isBroadcast:bool = True
|
||||||
# asBinary=(i % 2 == 0)
|
# asBinary=(i % 2 == 0)
|
||||||
success = testSend(
|
success = testSend(
|
||||||
interfaces[0], interfaces[1], isBroadcast, asBinary=False, wantAck=wantAck
|
interfaces[0], interfaces[1], isBroadcast, asBinary=False, wantAck=wantAck
|
||||||
@@ -126,10 +129,10 @@ def runTests(numTests=50, wantAck=False, maxFailures=0):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def testThread(numTests=50):
|
def testThread(numTests=50) -> bool:
|
||||||
"""Test thread"""
|
"""Test thread"""
|
||||||
logging.info("Found devices, starting tests...")
|
logging.info("Found devices, starting tests...")
|
||||||
result = runTests(numTests, wantAck=True)
|
result: bool = runTests(numTests, wantAck=True)
|
||||||
if result:
|
if result:
|
||||||
# Run another test
|
# Run another test
|
||||||
# Allow a few dropped packets
|
# Allow a few dropped packets
|
||||||
@@ -137,25 +140,25 @@ def testThread(numTests=50):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def onConnection(topic=pub.AUTO_TOPIC):
|
def onConnection(topic=pub.AUTO_TOPIC) -> None:
|
||||||
"""Callback invoked when we connect/disconnect from a radio"""
|
"""Callback invoked when we connect/disconnect from a radio"""
|
||||||
print(f"Connection changed: {topic.getName()}")
|
print(f"Connection changed: {topic.getName()}")
|
||||||
|
|
||||||
|
|
||||||
def openDebugLog(portName):
|
def openDebugLog(portName) -> io.TextIOWrapper:
|
||||||
"""Open the debug log file"""
|
"""Open the debug log file"""
|
||||||
debugname = "log" + portName.replace("/", "_")
|
debugname = "log" + portName.replace("/", "_")
|
||||||
logging.info(f"Writing serial debugging to {debugname}")
|
logging.info(f"Writing serial debugging to {debugname}")
|
||||||
return open(debugname, "w+", buffering=1, encoding="utf8")
|
return open(debugname, "w+", buffering=1, encoding="utf8")
|
||||||
|
|
||||||
|
|
||||||
def testAll(numTests=5):
|
def testAll(numTests: int=5) -> bool:
|
||||||
"""
|
"""
|
||||||
Run a series of tests using devices we can find.
|
Run a series of tests using devices we can find.
|
||||||
This is called from the cli with the "--test" option.
|
This is called from the cli with the "--test" option.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
ports = meshtastic.util.findPorts(True)
|
ports: List[str] = meshtastic.util.findPorts(True)
|
||||||
if len(ports) < 2:
|
if len(ports) < 2:
|
||||||
meshtastic.util.our_exit(
|
meshtastic.util.our_exit(
|
||||||
"Warning: Must have at least two devices connected to USB."
|
"Warning: Must have at least two devices connected to USB."
|
||||||
@@ -175,7 +178,7 @@ def testAll(numTests=5):
|
|||||||
)
|
)
|
||||||
|
|
||||||
logging.info("Ports opened, starting test")
|
logging.info("Ports opened, starting test")
|
||||||
result = testThread(numTests)
|
result: bool = testThread(numTests)
|
||||||
|
|
||||||
for i in interfaces:
|
for i in interfaces:
|
||||||
i.close()
|
i.close()
|
||||||
@@ -183,7 +186,7 @@ def testAll(numTests=5):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def testSimulator():
|
def testSimulator() -> None:
|
||||||
"""
|
"""
|
||||||
Assume that someone has launched meshtastic-native as a simulated node.
|
Assume that someone has launched meshtastic-native as a simulated node.
|
||||||
Talk to that node over TCP, do some operations and if they are successful
|
Talk to that node over TCP, do some operations and if they are successful
|
||||||
@@ -195,7 +198,7 @@ def testSimulator():
|
|||||||
logging.basicConfig(level=logging.DEBUG)
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
logging.info("Connecting to simulator on localhost!")
|
logging.info("Connecting to simulator on localhost!")
|
||||||
try:
|
try:
|
||||||
iface = TCPInterface("localhost")
|
iface: meshtastic.tcp_interface.TCPInterface = TCPInterface("localhost")
|
||||||
iface.showInfo()
|
iface.showInfo()
|
||||||
iface.localNode.showInfo()
|
iface.localNode.showInfo()
|
||||||
iface.localNode.exitSimulator()
|
iface.localNode.exitSimulator()
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ import sys
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from meshtastic.analysis.__main__ import main
|
try:
|
||||||
|
# Depends upon matplotlib & other packages in poetry's analysis group, not installed by default
|
||||||
|
from meshtastic.analysis.__main__ import main
|
||||||
|
except ImportError:
|
||||||
|
pytest.skip("Can't import meshtastic.analysis", allow_module_level=True)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ from meshtastic.__main__ import (
|
|||||||
onNode,
|
onNode,
|
||||||
onReceive,
|
onReceive,
|
||||||
tunnelMain,
|
tunnelMain,
|
||||||
|
set_missing_flags_false,
|
||||||
)
|
)
|
||||||
from meshtastic import mt_config
|
from meshtastic import mt_config
|
||||||
|
|
||||||
@@ -408,8 +409,8 @@ def test_main_nodes(capsys):
|
|||||||
|
|
||||||
iface = MagicMock(autospec=SerialInterface)
|
iface = MagicMock(autospec=SerialInterface)
|
||||||
|
|
||||||
def mock_showNodes():
|
def mock_showNodes(includeSelf, showFields):
|
||||||
print("inside mocked showNodes")
|
print(f"inside mocked showNodes: {includeSelf} {showFields}")
|
||||||
|
|
||||||
iface.showNodes.side_effect = mock_showNodes
|
iface.showNodes.side_effect = mock_showNodes
|
||||||
with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
|
with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
|
||||||
@@ -454,6 +455,37 @@ def test_main_set_owner_short_to_bob(capsys):
|
|||||||
assert err == ""
|
assert err == ""
|
||||||
mo.assert_called()
|
mo.assert_called()
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
|
def test_main_set_is_unmessageable_to_true(capsys):
|
||||||
|
"""Test --set-is-unmessageable true"""
|
||||||
|
sys.argv = ["", "--set-is-unmessageable", "true"]
|
||||||
|
mt_config.args = sys.argv
|
||||||
|
|
||||||
|
iface = MagicMock(autospec=SerialInterface)
|
||||||
|
with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
|
||||||
|
main()
|
||||||
|
out, err = capsys.readouterr()
|
||||||
|
assert re.search(r"Connected to radio", out, re.MULTILINE)
|
||||||
|
assert re.search(r"Setting device owner is_unmessageable to True", out, re.MULTILINE)
|
||||||
|
assert err == ""
|
||||||
|
mo.assert_called()
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
|
def test_main_set_is_unmessagable_to_true(capsys):
|
||||||
|
"""Test --set-is-unmessagable true"""
|
||||||
|
sys.argv = ["", "--set-is-unmessagable", "true"]
|
||||||
|
mt_config.args = sys.argv
|
||||||
|
|
||||||
|
iface = MagicMock(autospec=SerialInterface)
|
||||||
|
with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
|
||||||
|
main()
|
||||||
|
out, err = capsys.readouterr()
|
||||||
|
assert re.search(r"Connected to radio", out, re.MULTILINE)
|
||||||
|
assert re.search(r"Setting device owner is_unmessageable to True", out, re.MULTILINE)
|
||||||
|
assert err == ""
|
||||||
|
mo.assert_called()
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
@pytest.mark.usefixtures("reset_mt_config")
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
@@ -494,6 +526,44 @@ def test_main_get_canned_messages(capsys, caplog, iface_with_nodes):
|
|||||||
assert err == ""
|
assert err == ""
|
||||||
mo.assert_called()
|
mo.assert_called()
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
|
def test_main_set_ringtone(capsys):
|
||||||
|
"""Test --set-ringtone"""
|
||||||
|
sys.argv = ["", "--set-ringtone", "foo,bar"]
|
||||||
|
mt_config.args = sys.argv
|
||||||
|
|
||||||
|
iface = MagicMock(autospec=SerialInterface)
|
||||||
|
with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
|
||||||
|
main()
|
||||||
|
out, err = capsys.readouterr()
|
||||||
|
assert re.search(r"Connected to radio", out, re.MULTILINE)
|
||||||
|
assert re.search(r"Setting ringtone to foo,bar", out, re.MULTILINE)
|
||||||
|
assert err == ""
|
||||||
|
mo.assert_called()
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
|
def test_main_get_ringtone(capsys, caplog, iface_with_nodes):
|
||||||
|
"""Test --get-ringtone"""
|
||||||
|
sys.argv = ["", "--get-ringtone"]
|
||||||
|
mt_config.args = sys.argv
|
||||||
|
|
||||||
|
iface = iface_with_nodes
|
||||||
|
iface.devPath = "bar"
|
||||||
|
|
||||||
|
mocked_node = MagicMock(autospec=Node)
|
||||||
|
mocked_node.get_ringtone.return_value = "foo,bar"
|
||||||
|
iface.localNode = mocked_node
|
||||||
|
|
||||||
|
with caplog.at_level(logging.DEBUG):
|
||||||
|
with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
|
||||||
|
main()
|
||||||
|
out, err = capsys.readouterr()
|
||||||
|
assert re.search(r"Connected to radio", out, re.MULTILINE)
|
||||||
|
assert re.search(r"ringtone:foo,bar", out, re.MULTILINE)
|
||||||
|
assert err == ""
|
||||||
|
mo.assert_called()
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
@pytest.mark.usefixtures("reset_mt_config")
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
@@ -593,10 +663,10 @@ def test_main_sendtext(capsys):
|
|||||||
iface = MagicMock(autospec=SerialInterface)
|
iface = MagicMock(autospec=SerialInterface)
|
||||||
|
|
||||||
def mock_sendText(
|
def mock_sendText(
|
||||||
text, dest, wantAck=False, wantResponse=False, onResponse=None, channelIndex=0
|
text, dest, wantAck=False, wantResponse=False, onResponse=None, channelIndex=0, portNum=0
|
||||||
):
|
):
|
||||||
print("inside mocked sendText")
|
print("inside mocked sendText")
|
||||||
print(f"{text} {dest} {wantAck} {wantResponse} {channelIndex}")
|
print(f"{text} {dest} {wantAck} {wantResponse} {channelIndex} {portNum}")
|
||||||
|
|
||||||
iface.sendText.side_effect = mock_sendText
|
iface.sendText.side_effect = mock_sendText
|
||||||
|
|
||||||
@@ -620,10 +690,10 @@ def test_main_sendtext_with_channel(capsys):
|
|||||||
iface = MagicMock(autospec=SerialInterface)
|
iface = MagicMock(autospec=SerialInterface)
|
||||||
|
|
||||||
def mock_sendText(
|
def mock_sendText(
|
||||||
text, dest, wantAck=False, wantResponse=False, onResponse=None, channelIndex=0
|
text, dest, wantAck=False, wantResponse=False, onResponse=None, channelIndex=0, portNum=0
|
||||||
):
|
):
|
||||||
print("inside mocked sendText")
|
print("inside mocked sendText")
|
||||||
print(f"{text} {dest} {wantAck} {wantResponse} {channelIndex}")
|
print(f"{text} {dest} {wantAck} {wantResponse} {channelIndex} {portNum}")
|
||||||
|
|
||||||
iface.sendText.side_effect = mock_sendText
|
iface.sendText.side_effect = mock_sendText
|
||||||
|
|
||||||
@@ -1608,7 +1678,7 @@ def test_main_onReceive_empty(caplog, capsys):
|
|||||||
assert re.search(r"in onReceive", caplog.text, re.MULTILINE)
|
assert re.search(r"in onReceive", caplog.text, re.MULTILINE)
|
||||||
out, err = capsys.readouterr()
|
out, err = capsys.readouterr()
|
||||||
assert re.search(
|
assert re.search(
|
||||||
r"Warning: There is no field 'to' in the packet.", out, re.MULTILINE
|
r"Warning: Error processing received packet: 'to'.", out, re.MULTILINE
|
||||||
)
|
)
|
||||||
assert err == ""
|
assert err == ""
|
||||||
|
|
||||||
@@ -1724,6 +1794,8 @@ def test_main_export_config(capsys):
|
|||||||
mo.getLongName.return_value = "foo"
|
mo.getLongName.return_value = "foo"
|
||||||
mo.getShortName.return_value = "oof"
|
mo.getShortName.return_value = "oof"
|
||||||
mo.localNode.getURL.return_value = "bar"
|
mo.localNode.getURL.return_value = "bar"
|
||||||
|
mo.getCannedMessage.return_value = "foo|bar"
|
||||||
|
mo.getRingtone.return_value = "24:d=32,o=5"
|
||||||
mo.getMyNodeInfo().get.return_value = {
|
mo.getMyNodeInfo().get.return_value = {
|
||||||
"latitudeI": 1100000000,
|
"latitudeI": 1100000000,
|
||||||
"longitudeI": 1200000000,
|
"longitudeI": 1200000000,
|
||||||
@@ -1738,7 +1810,8 @@ position_broadcast_smart: true
|
|||||||
fixed_position: true
|
fixed_position: true
|
||||||
position_flags: 35"""
|
position_flags: 35"""
|
||||||
export_config(mo)
|
export_config(mo)
|
||||||
out, err = capsys.readouterr()
|
out = export_config(mo)
|
||||||
|
err = ""
|
||||||
|
|
||||||
# ensure we do not output this line
|
# ensure we do not output this line
|
||||||
assert not re.search(r"Connected to radio", out, re.MULTILINE)
|
assert not re.search(r"Connected to radio", out, re.MULTILINE)
|
||||||
@@ -1825,6 +1898,41 @@ position_flags: 35"""
|
|||||||
# mo.assert_called()
|
# mo.assert_called()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_set_missing_flags_false():
|
||||||
|
"""Test set_missing_flags_false() function"""
|
||||||
|
config = {
|
||||||
|
"bluetooth": {
|
||||||
|
"enabled": True
|
||||||
|
},
|
||||||
|
"lora": {
|
||||||
|
"txEnabled": True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false_defaults = {
|
||||||
|
("bluetooth", "enabled"),
|
||||||
|
("lora", "sx126xRxBoostedGain"),
|
||||||
|
("lora", "txEnabled"),
|
||||||
|
("lora", "usePreset"),
|
||||||
|
("position", "positionBroadcastSmartEnabled"),
|
||||||
|
("security", "serialEnabled"),
|
||||||
|
("mqtt", "encryptionEnabled"),
|
||||||
|
}
|
||||||
|
|
||||||
|
set_missing_flags_false(config, false_defaults)
|
||||||
|
|
||||||
|
# Preserved
|
||||||
|
assert config["bluetooth"]["enabled"] is True
|
||||||
|
assert config["lora"]["txEnabled"] is True
|
||||||
|
|
||||||
|
# Added
|
||||||
|
assert config["lora"]["usePreset"] is False
|
||||||
|
assert config["lora"]["sx126xRxBoostedGain"] is False
|
||||||
|
assert config["position"]["positionBroadcastSmartEnabled"] is False
|
||||||
|
assert config["security"]["serialEnabled"] is False
|
||||||
|
assert config["mqtt"]["encryptionEnabled"] is False
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
@pytest.mark.usefixtures("reset_mt_config")
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
def test_main_gpio_rd_no_gpio_channel(capsys):
|
def test_main_gpio_rd_no_gpio_channel(capsys):
|
||||||
@@ -2652,3 +2760,152 @@ def test_tunnel_tunnel_arg(
|
|||||||
out, err = capsys.readouterr()
|
out, err = capsys.readouterr()
|
||||||
assert re.search(r"Connected to radio", out, re.MULTILINE)
|
assert re.search(r"Connected to radio", out, re.MULTILINE)
|
||||||
assert err == ""
|
assert err == ""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
|
def test_set_favorite_node():
|
||||||
|
"""Test --set-favorite-node node"""
|
||||||
|
sys.argv = ["", "--set-favorite-node", "!12345678"]
|
||||||
|
mt_config.args = sys.argv
|
||||||
|
mocked_node = MagicMock(autospec=Node)
|
||||||
|
iface = MagicMock(autospec=SerialInterface)
|
||||||
|
iface.getNode.return_value = mocked_node
|
||||||
|
with patch("meshtastic.serial_interface.SerialInterface", return_value=iface):
|
||||||
|
main()
|
||||||
|
|
||||||
|
mocked_node.setFavorite.assert_called_once_with("!12345678")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
|
def test_remove_favorite_node():
|
||||||
|
"""Test --remove-favorite-node node"""
|
||||||
|
sys.argv = ["", "--remove-favorite-node", "!12345678"]
|
||||||
|
mt_config.args = sys.argv
|
||||||
|
mocked_node = MagicMock(autospec=Node)
|
||||||
|
iface = MagicMock(autospec=SerialInterface)
|
||||||
|
iface.getNode.return_value = mocked_node
|
||||||
|
mocked_node.iface = iface
|
||||||
|
with patch("meshtastic.serial_interface.SerialInterface", return_value=iface):
|
||||||
|
main()
|
||||||
|
|
||||||
|
mocked_node.removeFavorite.assert_called_once_with("!12345678")
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
|
def test_set_ignored_node():
|
||||||
|
"""Test --set-ignored-node node"""
|
||||||
|
sys.argv = ["", "--set-ignored-node", "!12345678"]
|
||||||
|
mt_config.args = sys.argv
|
||||||
|
mocked_node = MagicMock(autospec=Node)
|
||||||
|
iface = MagicMock(autospec=SerialInterface)
|
||||||
|
iface.getNode.return_value = mocked_node
|
||||||
|
with patch("meshtastic.serial_interface.SerialInterface", return_value=iface):
|
||||||
|
main()
|
||||||
|
|
||||||
|
mocked_node.setIgnored.assert_called_once_with("!12345678")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
|
def test_remove_ignored_node():
|
||||||
|
"""Test --remove-ignored-node node"""
|
||||||
|
sys.argv = ["", "--remove-ignored-node", "!12345678"]
|
||||||
|
mt_config.args = sys.argv
|
||||||
|
mocked_node = MagicMock(autospec=Node)
|
||||||
|
iface = MagicMock(autospec=SerialInterface)
|
||||||
|
iface.getNode.return_value = mocked_node
|
||||||
|
mocked_node.iface = iface
|
||||||
|
with patch("meshtastic.serial_interface.SerialInterface", return_value=iface):
|
||||||
|
main()
|
||||||
|
|
||||||
|
mocked_node.removeIgnored.assert_called_once_with("!12345678")
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
|
def test_main_set_owner_whitespace_only(capsys):
|
||||||
|
"""Test --set-owner with whitespace-only name"""
|
||||||
|
sys.argv = ["", "--set-owner", " "]
|
||||||
|
mt_config.args = sys.argv
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit) as excinfo:
|
||||||
|
main()
|
||||||
|
|
||||||
|
out, _ = capsys.readouterr()
|
||||||
|
assert "ERROR: Long Name cannot be empty or contain only whitespace characters" in out
|
||||||
|
assert excinfo.value.code == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
|
def test_main_set_owner_empty_string(capsys):
|
||||||
|
"""Test --set-owner with empty string"""
|
||||||
|
sys.argv = ["", "--set-owner", ""]
|
||||||
|
mt_config.args = sys.argv
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit) as excinfo:
|
||||||
|
main()
|
||||||
|
|
||||||
|
out, _ = capsys.readouterr()
|
||||||
|
assert "ERROR: Long Name cannot be empty or contain only whitespace characters" in out
|
||||||
|
assert excinfo.value.code == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
|
def test_main_set_owner_short_whitespace_only(capsys):
|
||||||
|
"""Test --set-owner-short with whitespace-only name"""
|
||||||
|
sys.argv = ["", "--set-owner-short", " "]
|
||||||
|
mt_config.args = sys.argv
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit) as excinfo:
|
||||||
|
main()
|
||||||
|
|
||||||
|
out, _ = capsys.readouterr()
|
||||||
|
assert "ERROR: Short Name cannot be empty or contain only whitespace characters" in out
|
||||||
|
assert excinfo.value.code == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
|
def test_main_set_owner_short_empty_string(capsys):
|
||||||
|
"""Test --set-owner-short with empty string"""
|
||||||
|
sys.argv = ["", "--set-owner-short", ""]
|
||||||
|
mt_config.args = sys.argv
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit) as excinfo:
|
||||||
|
main()
|
||||||
|
|
||||||
|
out, _ = capsys.readouterr()
|
||||||
|
assert "ERROR: Short Name cannot be empty or contain only whitespace characters" in out
|
||||||
|
assert excinfo.value.code == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
|
def test_main_set_ham_whitespace_only(capsys):
|
||||||
|
"""Test --set-ham with whitespace-only name"""
|
||||||
|
sys.argv = ["", "--set-ham", " "]
|
||||||
|
mt_config.args = sys.argv
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit) as excinfo:
|
||||||
|
main()
|
||||||
|
|
||||||
|
out, _ = capsys.readouterr()
|
||||||
|
assert "ERROR: Ham radio callsign cannot be empty or contain only whitespace characters" in out
|
||||||
|
assert excinfo.value.code == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
|
def test_main_set_ham_empty_string(capsys):
|
||||||
|
"""Test --set-ham with empty string"""
|
||||||
|
sys.argv = ["", "--set-ham", ""]
|
||||||
|
mt_config.args = sys.argv
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit) as excinfo:
|
||||||
|
main()
|
||||||
|
|
||||||
|
out, _ = capsys.readouterr()
|
||||||
|
assert "ERROR: Ham radio callsign cannot be empty or contain only whitespace characters" in out
|
||||||
|
assert excinfo.value.code == 1
|
||||||
|
|||||||
@@ -11,8 +11,12 @@ from ..protobuf import mesh_pb2, config_pb2
|
|||||||
from .. import BROADCAST_ADDR, LOCAL_ADDR
|
from .. import BROADCAST_ADDR, LOCAL_ADDR
|
||||||
from ..mesh_interface import MeshInterface, _timeago
|
from ..mesh_interface import MeshInterface, _timeago
|
||||||
from ..node import Node
|
from ..node import Node
|
||||||
from ..slog import LogSet
|
try:
|
||||||
from ..powermon import SimPowerSupply
|
# Depends upon the powermon group, not installed by default
|
||||||
|
from ..slog import LogSet
|
||||||
|
from ..powermon import SimPowerSupply
|
||||||
|
except ImportError:
|
||||||
|
pytest.skip("Can't import LogSet or SimPowerSupply", allow_module_level=True)
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
# from ..config import Config
|
# from ..config import Config
|
||||||
@@ -521,6 +525,28 @@ def test_getMyNodeInfo():
|
|||||||
myinfo = iface.getMyNodeInfo()
|
myinfo = iface.getMyNodeInfo()
|
||||||
assert myinfo == anode
|
assert myinfo == anode
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
|
def test_getCannedMessage():
|
||||||
|
"""Test MeshInterface.getCannedMessage()"""
|
||||||
|
iface = MeshInterface(noProto=True)
|
||||||
|
node = MagicMock()
|
||||||
|
node.get_canned_message.return_value = "Hi|Bye|Yes"
|
||||||
|
iface.localNode = node
|
||||||
|
result = iface.getCannedMessage()
|
||||||
|
assert result == "Hi|Bye|Yes"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
|
def test_getRingtone():
|
||||||
|
"""Test MeshInterface.getRingtone()"""
|
||||||
|
iface = MeshInterface(noProto=True)
|
||||||
|
node = MagicMock()
|
||||||
|
node.get_ringtone.return_value = "foo,bar"
|
||||||
|
iface.localNode = node
|
||||||
|
result = iface.getRingtone()
|
||||||
|
assert result == "foo,bar"
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
@pytest.mark.usefixtures("reset_mt_config")
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
@@ -539,7 +565,6 @@ def test_generatePacketId(capsys):
|
|||||||
assert err == ""
|
assert err == ""
|
||||||
assert pytest_wrapped_e.type == MeshInterface.MeshInterfaceError
|
assert pytest_wrapped_e.type == MeshInterface.MeshInterfaceError
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
@pytest.mark.usefixtures("reset_mt_config")
|
@pytest.mark.usefixtures("reset_mt_config")
|
||||||
def test_fixupPosition_empty_pos():
|
def test_fixupPosition_empty_pos():
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from unittest.mock import MagicMock, patch
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from ..protobuf import localonly_pb2, config_pb2
|
from ..protobuf import admin_pb2, localonly_pb2, config_pb2
|
||||||
from ..protobuf.channel_pb2 import Channel # pylint: disable=E0611
|
from ..protobuf.channel_pb2 import Channel # pylint: disable=E0611
|
||||||
from ..node import Node
|
from ..node import Node
|
||||||
from ..serial_interface import SerialInterface
|
from ..serial_interface import SerialInterface
|
||||||
@@ -270,7 +270,7 @@ def test_setURL_empty_url(capsys):
|
|||||||
assert pytest_wrapped_e.type == SystemExit
|
assert pytest_wrapped_e.type == SystemExit
|
||||||
assert pytest_wrapped_e.value.code == 1
|
assert pytest_wrapped_e.value.code == 1
|
||||||
out, err = capsys.readouterr()
|
out, err = capsys.readouterr()
|
||||||
assert re.search(r"Warning: There were no settings.", out, re.MULTILINE)
|
assert re.search(r"Warning: config or channels not loaded", out, re.MULTILINE)
|
||||||
assert err == ""
|
assert err == ""
|
||||||
|
|
||||||
|
|
||||||
@@ -304,7 +304,7 @@ def test_setURL_valid_URL_but_no_settings(capsys):
|
|||||||
assert pytest_wrapped_e.type == SystemExit
|
assert pytest_wrapped_e.type == SystemExit
|
||||||
assert pytest_wrapped_e.value.code == 1
|
assert pytest_wrapped_e.value.code == 1
|
||||||
out, err = capsys.readouterr()
|
out, err = capsys.readouterr()
|
||||||
assert re.search(r"Warning: There were no settings", out, re.MULTILINE)
|
assert re.search(r"Warning: config or channels not loaded", out, re.MULTILINE)
|
||||||
assert err == ""
|
assert err == ""
|
||||||
|
|
||||||
|
|
||||||
@@ -1254,8 +1254,7 @@ def test_requestChannels_non_localNode_starting_index(caplog):
|
|||||||
# },
|
# },
|
||||||
# 'id': 1692918436,
|
# 'id': 1692918436,
|
||||||
# 'hopLimit': 3,
|
# 'hopLimit': 3,
|
||||||
# 'priority':
|
# 'priority': 'RELIABLE',
|
||||||
# 'RELIABLE',
|
|
||||||
# 'raw': 'fake',
|
# 'raw': 'fake',
|
||||||
# 'fromId': '!9388f81c',
|
# 'fromId': '!9388f81c',
|
||||||
# 'toId': '!9388f81c'
|
# 'toId': '!9388f81c'
|
||||||
@@ -1426,6 +1425,131 @@ def test_requestChannels_non_localNode_starting_index(caplog):
|
|||||||
# assert err == ''
|
# assert err == ''
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.parametrize("favorite", ["!1dec0ded", 502009325])
|
||||||
|
def test_set_favorite(favorite):
|
||||||
|
"""Test setFavorite"""
|
||||||
|
iface = MagicMock(autospec=SerialInterface)
|
||||||
|
node = Node(iface, 12345678)
|
||||||
|
amesg = admin_pb2.AdminMessage()
|
||||||
|
with patch("meshtastic.admin_pb2.AdminMessage", return_value=amesg):
|
||||||
|
node.setFavorite(favorite)
|
||||||
|
assert amesg.set_favorite_node == 502009325
|
||||||
|
iface.sendData.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.parametrize("favorite", ["!1dec0ded", 502009325])
|
||||||
|
def test_remove_favorite(favorite):
|
||||||
|
"""Test setFavorite"""
|
||||||
|
iface = MagicMock(autospec=SerialInterface)
|
||||||
|
node = Node(iface, 12345678)
|
||||||
|
amesg = admin_pb2.AdminMessage()
|
||||||
|
with patch("meshtastic.admin_pb2.AdminMessage", return_value=amesg):
|
||||||
|
node.removeFavorite(favorite)
|
||||||
|
|
||||||
|
assert amesg.remove_favorite_node == 502009325
|
||||||
|
iface.sendData.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.parametrize("ignored", ["!1dec0ded", 502009325])
|
||||||
|
def test_set_ignored(ignored):
|
||||||
|
"""Test setFavorite"""
|
||||||
|
iface = MagicMock(autospec=SerialInterface)
|
||||||
|
node = Node(iface, 12345678)
|
||||||
|
amesg = admin_pb2.AdminMessage()
|
||||||
|
with patch("meshtastic.admin_pb2.AdminMessage", return_value=amesg):
|
||||||
|
node.setIgnored(ignored)
|
||||||
|
assert amesg.set_ignored_node == 502009325
|
||||||
|
iface.sendData.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
@pytest.mark.parametrize("ignored", ["!1dec0ded", 502009325])
|
||||||
|
def test_remove_ignored(ignored):
|
||||||
|
"""Test setFavorite"""
|
||||||
|
iface = MagicMock(autospec=SerialInterface)
|
||||||
|
node = Node(iface, 12345678)
|
||||||
|
amesg = admin_pb2.AdminMessage()
|
||||||
|
with patch("meshtastic.admin_pb2.AdminMessage", return_value=amesg):
|
||||||
|
node.removeIgnored(ignored)
|
||||||
|
|
||||||
|
assert amesg.remove_ignored_node == 502009325
|
||||||
|
iface.sendData.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_setOwner_whitespace_only_long_name(capsys):
|
||||||
|
"""Test setOwner with whitespace-only long name"""
|
||||||
|
iface = MagicMock(autospec=MeshInterface)
|
||||||
|
anode = Node(iface, 123, noProto=True)
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit) as excinfo:
|
||||||
|
anode.setOwner(long_name=" ")
|
||||||
|
|
||||||
|
out, _ = capsys.readouterr()
|
||||||
|
assert "ERROR: Long Name cannot be empty or contain only whitespace characters" in out
|
||||||
|
assert excinfo.value.code == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_setOwner_empty_long_name(capsys):
|
||||||
|
"""Test setOwner with empty long name"""
|
||||||
|
iface = MagicMock(autospec=MeshInterface)
|
||||||
|
anode = Node(iface, 123, noProto=True)
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit) as excinfo:
|
||||||
|
anode.setOwner(long_name="")
|
||||||
|
|
||||||
|
out, _ = capsys.readouterr()
|
||||||
|
assert "ERROR: Long Name cannot be empty or contain only whitespace characters" in out
|
||||||
|
assert excinfo.value.code == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_setOwner_whitespace_only_short_name(capsys):
|
||||||
|
"""Test setOwner with whitespace-only short name"""
|
||||||
|
iface = MagicMock(autospec=MeshInterface)
|
||||||
|
anode = Node(iface, 123, noProto=True)
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit) as excinfo:
|
||||||
|
anode.setOwner(short_name=" ")
|
||||||
|
|
||||||
|
out, _ = capsys.readouterr()
|
||||||
|
assert "ERROR: Short Name cannot be empty or contain only whitespace characters" in out
|
||||||
|
assert excinfo.value.code == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_setOwner_empty_short_name(capsys):
|
||||||
|
"""Test setOwner with empty short name"""
|
||||||
|
iface = MagicMock(autospec=MeshInterface)
|
||||||
|
anode = Node(iface, 123, noProto=True)
|
||||||
|
|
||||||
|
with pytest.raises(SystemExit) as excinfo:
|
||||||
|
anode.setOwner(short_name="")
|
||||||
|
|
||||||
|
out, _ = capsys.readouterr()
|
||||||
|
assert "ERROR: Short Name cannot be empty or contain only whitespace characters" in out
|
||||||
|
assert excinfo.value.code == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.unit
|
||||||
|
def test_setOwner_valid_names(caplog):
|
||||||
|
"""Test setOwner with valid names"""
|
||||||
|
iface = MagicMock(autospec=MeshInterface)
|
||||||
|
anode = Node(iface, 123, noProto=True)
|
||||||
|
|
||||||
|
with caplog.at_level(logging.DEBUG):
|
||||||
|
anode.setOwner(long_name="ValidName", short_name="VN")
|
||||||
|
|
||||||
|
# Should not raise any exceptions
|
||||||
|
# Note: When noProto=True, _sendAdmin is not called as the method returns early
|
||||||
|
assert re.search(r'p.set_owner.long_name:ValidName:', caplog.text, re.MULTILINE)
|
||||||
|
assert re.search(r'p.set_owner.short_name:VN:', caplog.text, re.MULTILINE)
|
||||||
|
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
# @pytest.mark.unitslow
|
# @pytest.mark.unitslow
|
||||||
# def test_waitForConfig():
|
# def test_waitForConfig():
|
||||||
|
|||||||
@@ -9,7 +9,11 @@ import pytest
|
|||||||
from meshtastic import mt_config
|
from meshtastic import mt_config
|
||||||
|
|
||||||
from ..tcp_interface import TCPInterface
|
from ..tcp_interface import TCPInterface
|
||||||
from ..tunnel import Tunnel, onTunnelReceive
|
try:
|
||||||
|
# Depends upon pytap2, not installed by default
|
||||||
|
from ..tunnel import Tunnel, onTunnelReceive
|
||||||
|
except ImportError:
|
||||||
|
pytest.skip("Can't import Tunnel or onTunnelReceive", allow_module_level=True)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
|
|||||||
@@ -442,6 +442,13 @@ def test_is_windows11_false_win8_1(patched_platform, patched_release):
|
|||||||
patched_platform.assert_called()
|
patched_platform.assert_called()
|
||||||
patched_release.assert_called()
|
patched_release.assert_called()
|
||||||
|
|
||||||
|
@patch("platform.release", return_value="2022Server")
|
||||||
|
@patch("platform.system", return_value="Windows")
|
||||||
|
def test_is_windows11_false_winserver(patched_platform, patched_release):
|
||||||
|
"""Test is_windows11()"""
|
||||||
|
assert is_windows11() is False
|
||||||
|
patched_platform.assert_called()
|
||||||
|
patched_release.assert_called()
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
@patch("platform.system", return_value="Linux")
|
@patch("platform.system", return_value="Linux")
|
||||||
@@ -556,7 +563,7 @@ def test_active_ports_on_supported_devices_mac_duplicates_check(mock_platform, m
|
|||||||
def test_message_to_json_shows_all():
|
def test_message_to_json_shows_all():
|
||||||
"""Test that message_to_json prints fields that aren't included in data passed in"""
|
"""Test that message_to_json prints fields that aren't included in data passed in"""
|
||||||
actual = json.loads(message_to_json(mesh_pb2.MyNodeInfo()))
|
actual = json.loads(message_to_json(mesh_pb2.MyNodeInfo()))
|
||||||
expected = { "myNodeNum": 0, "rebootCount": 0, "minAppVersion": 0 }
|
expected = { "myNodeNum": 0, "rebootCount": 0, "minAppVersion": 0, "deviceId": "", "pioEnv": "", 'firmwareEdition': 'VANILLA', 'nodedbCount': 0 }
|
||||||
assert actual == expected
|
assert actual == expected
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class Tunnel:
|
|||||||
self.message = message
|
self.message = message
|
||||||
super().__init__(self.message)
|
super().__init__(self.message)
|
||||||
|
|
||||||
def __init__(self, iface, subnet="10.115", netmask="255.255.0.0"):
|
def __init__(self, iface, subnet: str="10.115", netmask: str="255.255.0.0") -> None:
|
||||||
"""
|
"""
|
||||||
Constructor
|
Constructor
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import threading
|
|||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
from typing import List, NoReturn, Union
|
from typing import Any, Dict, List, NoReturn, Optional, Set, Tuple, Union
|
||||||
|
|
||||||
from google.protobuf.json_format import MessageToJson
|
from google.protobuf.json_format import MessageToJson
|
||||||
from google.protobuf.message import Message
|
from google.protobuf.message import Message
|
||||||
@@ -31,7 +31,7 @@ from meshtastic.version import get_active_version
|
|||||||
0925 Lakeview Research Saleae Logic (logic analyzer)
|
0925 Lakeview Research Saleae Logic (logic analyzer)
|
||||||
04b4:602a Cypress Semiconductor Corp. Hantek DSO-6022BL (oscilloscope)
|
04b4:602a Cypress Semiconductor Corp. Hantek DSO-6022BL (oscilloscope)
|
||||||
"""
|
"""
|
||||||
blacklistVids = dict.fromkeys([0x1366, 0x0483, 0x1915, 0x0925, 0x04b4])
|
blacklistVids: Dict = dict.fromkeys([0x1366, 0x0483, 0x1915, 0x0925, 0x04b4])
|
||||||
|
|
||||||
"""Some devices are highly likely to be meshtastic.
|
"""Some devices are highly likely to be meshtastic.
|
||||||
0x239a RAK4631
|
0x239a RAK4631
|
||||||
@@ -39,21 +39,21 @@ blacklistVids = dict.fromkeys([0x1366, 0x0483, 0x1915, 0x0925, 0x04b4])
|
|||||||
whitelistVids = dict.fromkeys([0x239a, 0x303a])
|
whitelistVids = dict.fromkeys([0x239a, 0x303a])
|
||||||
|
|
||||||
|
|
||||||
def quoteBooleans(a_string):
|
def quoteBooleans(a_string: str) -> str:
|
||||||
"""Quote booleans
|
"""Quote booleans
|
||||||
given a string that contains ": true", replace with ": 'true'" (or false)
|
given a string that contains ": true", replace with ": 'true'" (or false)
|
||||||
"""
|
"""
|
||||||
tmp = a_string.replace(": true", ": 'true'")
|
tmp: str = a_string.replace(": true", ": 'true'")
|
||||||
tmp = tmp.replace(": false", ": 'false'")
|
tmp = tmp.replace(": false", ": 'false'")
|
||||||
return tmp
|
return tmp
|
||||||
|
|
||||||
|
|
||||||
def genPSK256():
|
def genPSK256() -> bytes:
|
||||||
"""Generate a random preshared key"""
|
"""Generate a random preshared key"""
|
||||||
return os.urandom(32)
|
return os.urandom(32)
|
||||||
|
|
||||||
|
|
||||||
def fromPSK(valstr):
|
def fromPSK(valstr: str) -> Any:
|
||||||
"""A special version of fromStr that assumes the user is trying to set a PSK.
|
"""A special version of fromStr that assumes the user is trying to set a PSK.
|
||||||
In that case we also allow "none", "default" or "random" (to have python generate one), or simpleN
|
In that case we also allow "none", "default" or "random" (to have python generate one), or simpleN
|
||||||
"""
|
"""
|
||||||
@@ -70,7 +70,7 @@ def fromPSK(valstr):
|
|||||||
return fromStr(valstr)
|
return fromStr(valstr)
|
||||||
|
|
||||||
|
|
||||||
def fromStr(valstr):
|
def fromStr(valstr: str) -> Any:
|
||||||
"""Try to parse as int, float or bool (and fallback to a string as last resort)
|
"""Try to parse as int, float or bool (and fallback to a string as last resort)
|
||||||
|
|
||||||
Returns: an int, bool, float, str or byte array (for strings of hex digits)
|
Returns: an int, bool, float, str or byte array (for strings of hex digits)
|
||||||
@@ -78,6 +78,7 @@ def fromStr(valstr):
|
|||||||
Args:
|
Args:
|
||||||
valstr (string): A user provided string
|
valstr (string): A user provided string
|
||||||
"""
|
"""
|
||||||
|
val: Any
|
||||||
if len(valstr) == 0: # Treat an emptystring as an empty bytes
|
if len(valstr) == 0: # Treat an emptystring as an empty bytes
|
||||||
val = bytes()
|
val = bytes()
|
||||||
elif valstr.startswith("0x"):
|
elif valstr.startswith("0x"):
|
||||||
@@ -100,7 +101,15 @@ def fromStr(valstr):
|
|||||||
return val
|
return val
|
||||||
|
|
||||||
|
|
||||||
def pskToString(psk: bytes):
|
|
||||||
|
def toStr(raw_value):
|
||||||
|
"""Convert a value to a string that can be used in a config file"""
|
||||||
|
if isinstance(raw_value, bytes):
|
||||||
|
return "base64:" + base64.b64encode(raw_value).decode("utf-8")
|
||||||
|
return str(raw_value)
|
||||||
|
|
||||||
|
|
||||||
|
def pskToString(psk: bytes) -> str:
|
||||||
"""Given an array of PSK bytes, decode them into a human readable (but privacy protecting) string"""
|
"""Given an array of PSK bytes, decode them into a human readable (but privacy protecting) string"""
|
||||||
if len(psk) == 0:
|
if len(psk) == 0:
|
||||||
return "unencrypted"
|
return "unencrypted"
|
||||||
@@ -122,12 +131,12 @@ def stripnl(s) -> str:
|
|||||||
return " ".join(s.split())
|
return " ".join(s.split())
|
||||||
|
|
||||||
|
|
||||||
def fixme(message):
|
def fixme(message: str) -> None:
|
||||||
"""Raise an exception for things that needs to be fixed"""
|
"""Raise an exception for things that needs to be fixed"""
|
||||||
raise Exception(f"FIXME: {message}") # pylint: disable=W0719
|
raise Exception(f"FIXME: {message}") # pylint: disable=W0719
|
||||||
|
|
||||||
|
|
||||||
def catchAndIgnore(reason, closure):
|
def catchAndIgnore(reason: str, closure) -> None:
|
||||||
"""Call a closure but if it throws an exception print it and continue"""
|
"""Call a closure but if it throws an exception print it and continue"""
|
||||||
try:
|
try:
|
||||||
closure()
|
closure()
|
||||||
@@ -145,7 +154,7 @@ def findPorts(eliminate_duplicates: bool=False) -> List[str]:
|
|||||||
all_ports = serial.tools.list_ports.comports()
|
all_ports = serial.tools.list_ports.comports()
|
||||||
|
|
||||||
# look for 'likely' meshtastic devices
|
# look for 'likely' meshtastic devices
|
||||||
ports = list(
|
ports: List = list(
|
||||||
map(
|
map(
|
||||||
lambda port: port.device,
|
lambda port: port.device,
|
||||||
filter(
|
filter(
|
||||||
@@ -184,14 +193,14 @@ class dotdict(dict):
|
|||||||
class Timeout:
|
class Timeout:
|
||||||
"""Timeout class"""
|
"""Timeout class"""
|
||||||
|
|
||||||
def __init__(self, maxSecs: int=20):
|
def __init__(self, maxSecs: int=20) -> None:
|
||||||
self.expireTime: Union[int, float] = 0
|
self.expireTime: Union[int, float] = 0
|
||||||
self.sleepInterval: float = 0.1
|
self.sleepInterval: float = 0.1
|
||||||
self.expireTimeout: int = maxSecs
|
self.expireTimeout: int = maxSecs
|
||||||
|
|
||||||
def reset(self):
|
def reset(self, expireTimeout=None):
|
||||||
"""Restart the waitForSet timer"""
|
"""Restart the waitForSet timer"""
|
||||||
self.expireTime = time.time() + self.expireTimeout
|
self.expireTime = time.time() + (self.expireTimeout if expireTimeout is None else expireTimeout)
|
||||||
|
|
||||||
def waitForSet(self, target, attrs=()) -> bool:
|
def waitForSet(self, target, attrs=()) -> bool:
|
||||||
"""Block until the specified attributes are set. Returns True if config has been received."""
|
"""Block until the specified attributes are set. Returns True if config has been received."""
|
||||||
@@ -216,8 +225,7 @@ class Timeout:
|
|||||||
|
|
||||||
def waitForTraceRoute(self, waitFactor, acknowledgment, attr="receivedTraceRoute") -> bool:
|
def waitForTraceRoute(self, waitFactor, acknowledgment, attr="receivedTraceRoute") -> bool:
|
||||||
"""Block until traceroute response is received. Returns True if traceroute response has been received."""
|
"""Block until traceroute response is received. Returns True if traceroute response has been received."""
|
||||||
self.expireTimeout *= waitFactor
|
self.reset(self.expireTimeout * waitFactor)
|
||||||
self.reset()
|
|
||||||
while time.time() < self.expireTime:
|
while time.time() < self.expireTime:
|
||||||
if getattr(acknowledgment, attr, None):
|
if getattr(acknowledgment, attr, None):
|
||||||
acknowledgment.reset()
|
acknowledgment.reset()
|
||||||
@@ -245,10 +253,20 @@ class Timeout:
|
|||||||
time.sleep(self.sleepInterval)
|
time.sleep(self.sleepInterval)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def waitForWaypoint(self, acknowledgment) -> bool:
|
||||||
|
"""Block until waypoint response is received. Returns True if waypoint response has been received."""
|
||||||
|
self.reset()
|
||||||
|
while time.time() < self.expireTime:
|
||||||
|
if getattr(acknowledgment, "receivedWaypoint", None):
|
||||||
|
acknowledgment.reset()
|
||||||
|
return True
|
||||||
|
time.sleep(self.sleepInterval)
|
||||||
|
return False
|
||||||
|
|
||||||
class Acknowledgment:
|
class Acknowledgment:
|
||||||
"A class that records which type of acknowledgment was just received, if any."
|
"A class that records which type of acknowledgment was just received, if any."
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
"""initialize"""
|
"""initialize"""
|
||||||
self.receivedAck = False
|
self.receivedAck = False
|
||||||
self.receivedNak = False
|
self.receivedNak = False
|
||||||
@@ -256,8 +274,9 @@ class Acknowledgment:
|
|||||||
self.receivedTraceRoute = False
|
self.receivedTraceRoute = False
|
||||||
self.receivedTelemetry = False
|
self.receivedTelemetry = False
|
||||||
self.receivedPosition = False
|
self.receivedPosition = False
|
||||||
|
self.receivedWaypoint = False
|
||||||
|
|
||||||
def reset(self):
|
def reset(self) -> None:
|
||||||
"""reset"""
|
"""reset"""
|
||||||
self.receivedAck = False
|
self.receivedAck = False
|
||||||
self.receivedNak = False
|
self.receivedNak = False
|
||||||
@@ -265,23 +284,24 @@ class Acknowledgment:
|
|||||||
self.receivedTraceRoute = False
|
self.receivedTraceRoute = False
|
||||||
self.receivedTelemetry = False
|
self.receivedTelemetry = False
|
||||||
self.receivedPosition = False
|
self.receivedPosition = False
|
||||||
|
self.receivedWaypoint = False
|
||||||
|
|
||||||
|
|
||||||
class DeferredExecution:
|
class DeferredExecution:
|
||||||
"""A thread that accepts closures to run, and runs them as they are received"""
|
"""A thread that accepts closures to run, and runs them as they are received"""
|
||||||
|
|
||||||
def __init__(self, name):
|
def __init__(self, name) -> None:
|
||||||
self.queue = Queue()
|
self.queue: Queue = Queue()
|
||||||
# this thread must be marked as daemon, otherwise it will prevent clients from exiting
|
# this thread must be marked as daemon, otherwise it will prevent clients from exiting
|
||||||
self.thread = threading.Thread(target=self._run, args=(), name=name, daemon=True)
|
self.thread = threading.Thread(target=self._run, args=(), name=name, daemon=True)
|
||||||
self.thread.daemon = True
|
self.thread.daemon = True
|
||||||
self.thread.start()
|
self.thread.start()
|
||||||
|
|
||||||
def queueWork(self, runnable):
|
def queueWork(self, runnable) -> None:
|
||||||
"""Queue up the work"""
|
"""Queue up the work"""
|
||||||
self.queue.put(runnable)
|
self.queue.put(runnable)
|
||||||
|
|
||||||
def _run(self):
|
def _run(self) -> None:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
o = self.queue.get()
|
o = self.queue.get()
|
||||||
@@ -301,7 +321,7 @@ def our_exit(message, return_value=1) -> NoReturn:
|
|||||||
sys.exit(return_value)
|
sys.exit(return_value)
|
||||||
|
|
||||||
|
|
||||||
def support_info():
|
def support_info() -> None:
|
||||||
"""Print out info that helps troubleshooting of the cli."""
|
"""Print out info that helps troubleshooting of the cli."""
|
||||||
print("")
|
print("")
|
||||||
print("If having issues with meshtastic cli or python library")
|
print("If having issues with meshtastic cli or python library")
|
||||||
@@ -330,7 +350,7 @@ def support_info():
|
|||||||
print("Please add the output from the command: meshtastic --info")
|
print("Please add the output from the command: meshtastic --info")
|
||||||
|
|
||||||
|
|
||||||
def remove_keys_from_dict(keys, adict):
|
def remove_keys_from_dict(keys: Union[Tuple, List, Set], adict: Dict) -> Dict:
|
||||||
"""Return a dictionary without some keys in it.
|
"""Return a dictionary without some keys in it.
|
||||||
Will removed nested keys.
|
Will removed nested keys.
|
||||||
"""
|
"""
|
||||||
@@ -345,33 +365,33 @@ def remove_keys_from_dict(keys, adict):
|
|||||||
return adict
|
return adict
|
||||||
|
|
||||||
|
|
||||||
def hexstr(barray):
|
def hexstr(barray: bytes) -> str:
|
||||||
"""Print a string of hex digits"""
|
"""Print a string of hex digits"""
|
||||||
return ":".join(f"{x:02x}" for x in barray)
|
return ":".join(f"{x:02x}" for x in barray)
|
||||||
|
|
||||||
|
|
||||||
def ipstr(barray):
|
def ipstr(barray: bytes) -> str:
|
||||||
"""Print a string of ip digits"""
|
"""Print a string of ip digits"""
|
||||||
return ".".join(f"{x}" for x in barray)
|
return ".".join(f"{x}" for x in barray)
|
||||||
|
|
||||||
|
|
||||||
def readnet_u16(p, offset):
|
def readnet_u16(p, offset: int) -> int:
|
||||||
"""Read big endian u16 (network byte order)"""
|
"""Read big endian u16 (network byte order)"""
|
||||||
return p[offset] * 256 + p[offset + 1]
|
return p[offset] * 256 + p[offset + 1]
|
||||||
|
|
||||||
|
|
||||||
def convert_mac_addr(val):
|
def convert_mac_addr(val: str) -> Union[str, bytes]:
|
||||||
"""Convert the base 64 encoded value to a mac address
|
"""Convert the base 64 encoded value to a mac address
|
||||||
val - base64 encoded value (ex: '/c0gFyhb'))
|
val - base64 encoded value (ex: '/c0gFyhb'))
|
||||||
returns: a string formatted like a mac address (ex: 'fd:cd:20:17:28:5b')
|
returns: a string formatted like a mac address (ex: 'fd:cd:20:17:28:5b')
|
||||||
"""
|
"""
|
||||||
if not re.match("[0-9a-f]{2}([-:]?)[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", val):
|
if not re.match("[0-9a-f]{2}([-:]?)[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", val):
|
||||||
val_as_bytes = base64.b64decode(val)
|
val_as_bytes: bytes = base64.b64decode(val)
|
||||||
return hexstr(val_as_bytes)
|
return hexstr(val_as_bytes)
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
|
||||||
def snake_to_camel(a_string):
|
def snake_to_camel(a_string: str) -> str:
|
||||||
"""convert snake_case to camelCase"""
|
"""convert snake_case to camelCase"""
|
||||||
# split underscore using split
|
# split underscore using split
|
||||||
temp = a_string.split("_")
|
temp = a_string.split("_")
|
||||||
@@ -380,16 +400,16 @@ def snake_to_camel(a_string):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def camel_to_snake(a_string):
|
def camel_to_snake(a_string: str) -> str:
|
||||||
"""convert camelCase to snake_case"""
|
"""convert camelCase to snake_case"""
|
||||||
return "".join(["_" + i.lower() if i.isupper() else i for i in a_string]).lstrip(
|
return "".join(["_" + i.lower() if i.isupper() else i for i in a_string]).lstrip(
|
||||||
"_"
|
"_"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def detect_supported_devices():
|
def detect_supported_devices() -> Set:
|
||||||
"""detect supported devices based on vendor id"""
|
"""detect supported devices based on vendor id"""
|
||||||
system = platform.system()
|
system: str = platform.system()
|
||||||
# print(f'system:{system}')
|
# print(f'system:{system}')
|
||||||
|
|
||||||
possible_devices = set()
|
possible_devices = set()
|
||||||
@@ -447,9 +467,9 @@ def detect_supported_devices():
|
|||||||
return possible_devices
|
return possible_devices
|
||||||
|
|
||||||
|
|
||||||
def detect_windows_needs_driver(sd, print_reason=False):
|
def detect_windows_needs_driver(sd, print_reason=False) -> bool:
|
||||||
"""detect if Windows user needs to install driver for a supported device"""
|
"""detect if Windows user needs to install driver for a supported device"""
|
||||||
need_to_install_driver = False
|
need_to_install_driver: bool = False
|
||||||
|
|
||||||
if sd:
|
if sd:
|
||||||
system = platform.system()
|
system = platform.system()
|
||||||
@@ -475,7 +495,7 @@ def detect_windows_needs_driver(sd, print_reason=False):
|
|||||||
return need_to_install_driver
|
return need_to_install_driver
|
||||||
|
|
||||||
|
|
||||||
def eliminate_duplicate_port(ports):
|
def eliminate_duplicate_port(ports: List) -> List:
|
||||||
"""Sometimes we detect 2 serial ports, but we really only need to use one of the ports.
|
"""Sometimes we detect 2 serial ports, but we really only need to use one of the ports.
|
||||||
|
|
||||||
ports is a list of ports
|
ports is a list of ports
|
||||||
@@ -508,23 +528,23 @@ def eliminate_duplicate_port(ports):
|
|||||||
return new_ports
|
return new_ports
|
||||||
|
|
||||||
|
|
||||||
def is_windows11():
|
def is_windows11() -> bool:
|
||||||
"""Detect if Windows 11"""
|
"""Detect if Windows 11"""
|
||||||
is_win11 = False
|
is_win11: bool = False
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
if float(platform.release()) >= 10.0:
|
try:
|
||||||
patch = platform.version().split(".")[2]
|
if float(platform.release()) >= 10.0:
|
||||||
# in case they add some number suffix later, just get first 5 chars of patch
|
patch = platform.version().split(".")[2]
|
||||||
patch = patch[:5]
|
# in case they add some number suffix later, just get first 5 chars of patch
|
||||||
try:
|
patch = patch[:5]
|
||||||
if int(patch) >= 22000:
|
if int(patch) >= 22000:
|
||||||
is_win11 = True
|
is_win11 = True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"problem detecting win11 e:{e}")
|
print(f"problem detecting win11 e:{e}")
|
||||||
return is_win11
|
return is_win11
|
||||||
|
|
||||||
|
|
||||||
def get_unique_vendor_ids():
|
def get_unique_vendor_ids() -> Set[str]:
|
||||||
"""Return a set of unique vendor ids"""
|
"""Return a set of unique vendor ids"""
|
||||||
vids = set()
|
vids = set()
|
||||||
for d in supported_devices:
|
for d in supported_devices:
|
||||||
@@ -533,7 +553,7 @@ def get_unique_vendor_ids():
|
|||||||
return vids
|
return vids
|
||||||
|
|
||||||
|
|
||||||
def get_devices_with_vendor_id(vid):
|
def get_devices_with_vendor_id(vid: str) -> Set: #Set[SupportedDevice]
|
||||||
"""Return a set of unique devices with the vendor id"""
|
"""Return a set of unique devices with the vendor id"""
|
||||||
sd = set()
|
sd = set()
|
||||||
for d in supported_devices:
|
for d in supported_devices:
|
||||||
@@ -542,11 +562,11 @@ def get_devices_with_vendor_id(vid):
|
|||||||
return sd
|
return sd
|
||||||
|
|
||||||
|
|
||||||
def active_ports_on_supported_devices(sds, eliminate_duplicates=False):
|
def active_ports_on_supported_devices(sds, eliminate_duplicates=False) -> Set[str]:
|
||||||
"""Return a set of active ports based on the supplied supported devices"""
|
"""Return a set of active ports based on the supplied supported devices"""
|
||||||
ports = set()
|
ports: Set = set()
|
||||||
baseports = set()
|
baseports: Set = set()
|
||||||
system = platform.system()
|
system: str = platform.system()
|
||||||
|
|
||||||
# figure out what possible base ports there are
|
# figure out what possible base ports there are
|
||||||
for d in sds:
|
for d in sds:
|
||||||
@@ -604,13 +624,13 @@ def active_ports_on_supported_devices(sds, eliminate_duplicates=False):
|
|||||||
for com_port in com_ports:
|
for com_port in com_ports:
|
||||||
ports.add(com_port)
|
ports.add(com_port)
|
||||||
if eliminate_duplicates:
|
if eliminate_duplicates:
|
||||||
ports = eliminate_duplicate_port(list(ports))
|
portlist: List = eliminate_duplicate_port(list(ports))
|
||||||
ports.sort()
|
portlist.sort()
|
||||||
ports = set(ports)
|
ports = set(portlist)
|
||||||
return ports
|
return ports
|
||||||
|
|
||||||
|
|
||||||
def detect_windows_port(sd):
|
def detect_windows_port(sd) -> Set[str]: #"sd" is a SupportedDevice from meshtastic.supported_device
|
||||||
"""detect if Windows port"""
|
"""detect if Windows port"""
|
||||||
ports = set()
|
ports = set()
|
||||||
|
|
||||||
@@ -635,20 +655,26 @@ def detect_windows_port(sd):
|
|||||||
return ports
|
return ports
|
||||||
|
|
||||||
|
|
||||||
def check_if_newer_version():
|
def check_if_newer_version() -> Optional[str]:
|
||||||
"""Check pip to see if we are running the latest version."""
|
"""Check pip to see if we are running the latest version."""
|
||||||
pypi_version = None
|
pypi_version: Optional[str] = None
|
||||||
try:
|
try:
|
||||||
url = "https://pypi.org/pypi/meshtastic/json"
|
url: str = "https://pypi.org/pypi/meshtastic/json"
|
||||||
data = requests.get(url, timeout=5).json()
|
data = requests.get(url, timeout=5).json()
|
||||||
pypi_version = data["info"]["version"]
|
pypi_version = data["info"]["version"]
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
act_version = get_active_version()
|
act_version = get_active_version()
|
||||||
|
|
||||||
|
if pypi_version is None:
|
||||||
|
return None
|
||||||
try:
|
try:
|
||||||
parsed_act_version = pkg_version.parse(act_version)
|
parsed_act_version = pkg_version.parse(act_version)
|
||||||
parsed_pypi_version = pkg_version.parse(pypi_version)
|
parsed_pypi_version = pkg_version.parse(pypi_version)
|
||||||
|
#Note: if handed "None" when we can't download the pypi_version,
|
||||||
|
#this gets a TypeError:
|
||||||
|
#"TypeError: expected string or bytes-like object, got 'NoneType'"
|
||||||
|
#Handle that below?
|
||||||
except pkg_version.InvalidVersion:
|
except pkg_version.InvalidVersion:
|
||||||
return pypi_version
|
return pypi_version
|
||||||
|
|
||||||
@@ -660,5 +686,8 @@ def check_if_newer_version():
|
|||||||
|
|
||||||
def message_to_json(message: Message, multiline: bool=False) -> str:
|
def message_to_json(message: Message, multiline: bool=False) -> str:
|
||||||
"""Return protobuf message as JSON. Always print all fields, even when not present in data."""
|
"""Return protobuf message as JSON. Always print all fields, even when not present in data."""
|
||||||
json = MessageToJson(message, always_print_fields_with_no_presence=True)
|
try:
|
||||||
|
json = MessageToJson(message, always_print_fields_with_no_presence=True)
|
||||||
|
except TypeError:
|
||||||
|
json = MessageToJson(message, including_default_value_fields=True) # type: ignore[call-arg] # pylint: disable=E1123
|
||||||
return stripnl(json) if not multiline else json
|
return stripnl(json) if not multiline else json
|
||||||
|
|||||||
1570
poetry.lock
generated
1570
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
Submodule protobufs updated: 83c78e26e3...34f0c8115d
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "meshtastic"
|
name = "meshtastic"
|
||||||
version = "2.5.3"
|
version = "2.7.2"
|
||||||
description = "Python API & client shell for talking to Meshtastic devices"
|
description = "Python API & client shell for talking to Meshtastic devices"
|
||||||
authors = ["Meshtastic Developers <contact@meshtastic.org>"]
|
authors = ["Meshtastic Developers <contact@meshtastic.org>"]
|
||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
@@ -9,24 +9,23 @@ readme = "README.md"
|
|||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.9,<3.14" # 3.9 is needed for pandas, bleak requires <3.14
|
python = "^3.9,<3.14" # 3.9 is needed for pandas, bleak requires <3.14
|
||||||
pyserial = "^3.5"
|
pyserial = "^3.5"
|
||||||
protobuf = ">=5.26.0"
|
protobuf = ">=4.21.12"
|
||||||
dotmap = "^1.3.30"
|
|
||||||
pexpect = "^4.9.0"
|
|
||||||
pyqrcode = "^1.2.1"
|
|
||||||
tabulate = "^0.9.0"
|
tabulate = "^0.9.0"
|
||||||
webencodings = "^0.5.1"
|
|
||||||
requests = "^2.31.0"
|
requests = "^2.31.0"
|
||||||
pyparsing = "^3.1.2"
|
|
||||||
pyyaml = "^6.0.1"
|
pyyaml = "^6.0.1"
|
||||||
pypubsub = "^4.0.3"
|
pypubsub = "^4.0.3"
|
||||||
bleak = "^0.22.3"
|
bleak = "^0.22.3"
|
||||||
packaging = "^24.0"
|
packaging = "^24.0"
|
||||||
print-color = "^0.4.6"
|
argcomplete = { version = "^3.5.2", optional = true }
|
||||||
|
pyqrcode = { version = "^1.2.1", optional = true }
|
||||||
|
dotmap = { version = "^1.3.30", optional = true }
|
||||||
|
print-color = { version = "^0.4.6", optional = true }
|
||||||
dash = { version = "^2.17.1", optional = true }
|
dash = { version = "^2.17.1", optional = true }
|
||||||
pytap2 = { version = "^2.3.0", optional = true }
|
pytap2 = { version = "^2.3.0", optional = true }
|
||||||
dash-bootstrap-components = { version = "^1.6.0", optional = true }
|
dash-bootstrap-components = { version = "^1.6.0", optional = true }
|
||||||
pandas = { version = "^2.2.2", optional = true }
|
pandas = { version = "^2.2.2", optional = true }
|
||||||
pandas-stubs = { version = "^2.2.2.240603", optional = true }
|
pandas-stubs = { version = "^2.2.2.240603", optional = true }
|
||||||
|
wcwidth = {version = "^0.2.13", optional = true}
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
hypothesis = "^6.103.2"
|
hypothesis = "^6.103.2"
|
||||||
@@ -37,7 +36,7 @@ autopep8 = "^2.1.0"
|
|||||||
pylint = "^3.2.3"
|
pylint = "^3.2.3"
|
||||||
pyinstaller = "^6.8.0"
|
pyinstaller = "^6.8.0"
|
||||||
mypy = "^1.10.0"
|
mypy = "^1.10.0"
|
||||||
mypy-protobuf = "^3.6.0"
|
mypy-protobuf = "^3.3.0"
|
||||||
types-protobuf = "^5.26.0.20240422"
|
types-protobuf = "^5.26.0.20240422"
|
||||||
types-tabulate = "^0.9.0.20240106"
|
types-tabulate = "^0.9.0.20240106"
|
||||||
types-requests = "^2.31.0.20240406"
|
types-requests = "^2.31.0.20240406"
|
||||||
@@ -67,6 +66,7 @@ ipywidgets = "^8.1.3"
|
|||||||
jupyterlab-widgets = "^3.0.11"
|
jupyterlab-widgets = "^3.0.11"
|
||||||
|
|
||||||
[tool.poetry.extras]
|
[tool.poetry.extras]
|
||||||
|
cli = ["pyqrcode", "print-color", "dotmap", "argcomplete", "wcwidth"]
|
||||||
tunnel = ["pytap2"]
|
tunnel = ["pytap2"]
|
||||||
analysis = ["dash", "dash-bootstrap-components", "pandas", "pandas-stubs"]
|
analysis = ["dash", "dash-bootstrap-components", "pandas", "pandas-stubs"]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user