mirror of
https://github.com/meshtastic/python.git
synced 2025-12-26 17:37:51 -05:00
Compare commits
280 Commits
2.4.0
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf89edf106 | ||
|
|
622a435465 | ||
|
|
56680f8da6 | ||
|
|
321a960c13 | ||
|
|
4668852b0b | ||
|
|
c3973117c8 | ||
|
|
d456e4ce30 | ||
|
|
ec78f62992 | ||
|
|
dfc9547ffc | ||
|
|
ee0f73a20e | ||
|
|
2e73fe310c | ||
|
|
d4bc39153a | ||
|
|
2e8f823431 | ||
|
|
675169167c | ||
|
|
75f8e27799 | ||
|
|
f426699d2b | ||
|
|
bc1664dade | ||
|
|
32a61b0209 | ||
|
|
0c38a9eb0b | ||
|
|
e591cc184f | ||
|
|
b42d33824a | ||
|
|
ed908fc4b6 | ||
|
|
3710e6e909 | ||
|
|
faa8064ccc | ||
|
|
2f44351945 | ||
|
|
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 | ||
|
|
f08ec1885b | ||
|
|
feca49faed | ||
|
|
dfaf1a275d | ||
|
|
da7fa31805 | ||
|
|
12fd29b203 | ||
|
|
a43dd201ba | ||
|
|
a64a9d203a | ||
|
|
10136962d7 | ||
|
|
3afb294f9b | ||
|
|
ee405fec41 | ||
|
|
3eabaf91d0 | ||
|
|
78b92cecc9 | ||
|
|
7088b90514 | ||
|
|
2ae81f8602 | ||
|
|
923f5e82d0 | ||
|
|
05731128fa | ||
|
|
0523d4c94f | ||
|
|
90e901de79 | ||
|
|
6606851135 | ||
|
|
33fecbd74d | ||
|
|
6b9db7abd9 | ||
|
|
ece6286d82 | ||
|
|
e335f12a3b | ||
|
|
0da405168f | ||
|
|
58d9039a04 | ||
|
|
f77e788aa8 | ||
|
|
aba381fb54 | ||
|
|
0bb4b31b6a | ||
|
|
915066e0af | ||
|
|
6be3969577 | ||
|
|
b73cc1f499 | ||
|
|
65305af184 | ||
|
|
3fb1e67357 | ||
|
|
cbd3c119fe | ||
|
|
bbd6d6a541 | ||
|
|
6e1217c7ca | ||
|
|
81db38956b | ||
|
|
27729995d2 | ||
|
|
d875a574b6 | ||
|
|
40019a9712 | ||
|
|
de657bab24 | ||
|
|
40353a387e | ||
|
|
9949d144a1 | ||
|
|
48a06c6e1e | ||
|
|
c696d59b90 | ||
|
|
4fdbcb9679 | ||
|
|
5d6dfb877b | ||
|
|
951edfe27b | ||
|
|
5cc9627e21 | ||
|
|
bf904c6906 | ||
|
|
2026212a00 | ||
|
|
34f9be255e | ||
|
|
e561222ea7 | ||
|
|
73a1bbc7d5 | ||
|
|
8f2c397fbf | ||
|
|
62f5201a38 | ||
|
|
9e7d5e96ab | ||
|
|
aa74db46cb | ||
|
|
1967519deb | ||
|
|
662aea049a | ||
|
|
44cfd72a80 | ||
|
|
abe1dd47ca | ||
|
|
584a14f578 | ||
|
|
f7724295f9 | ||
|
|
cc2067b729 | ||
|
|
180ddbcd1a | ||
|
|
3bbd02c915 | ||
|
|
23e6eca056 | ||
|
|
21ff4a1a4a | ||
|
|
ef6db0e48c | ||
|
|
43b0993aaa | ||
|
|
9423a8a8b9 | ||
|
|
33a13f715e | ||
|
|
0aac077ce7 | ||
|
|
8ba92da7cf | ||
|
|
0d26c26f7e | ||
|
|
aa6f09635a | ||
|
|
83b0dcad56 | ||
|
|
78d8403bbd | ||
|
|
0813e8dba6 | ||
|
|
23bb2e26f9 | ||
|
|
399dd477b8 | ||
|
|
b59ecff272 | ||
|
|
17f3605736 | ||
|
|
a689fd73a2 | ||
|
|
da30e1141a | ||
|
|
3811226a61 | ||
|
|
b6547c9737 | ||
|
|
9612aea9b9 | ||
|
|
b4bd9568e4 | ||
|
|
aed4f25cf5 | ||
|
|
5c312bedc1 | ||
|
|
428e9a228c | ||
|
|
4500850063 | ||
|
|
aedaa3748d | ||
|
|
4b60c5b457 | ||
|
|
c92474cf36 | ||
|
|
b2acc84717 | ||
|
|
1981f0e899 | ||
|
|
bcce5687c5 | ||
|
|
b9d805057f | ||
|
|
d77335caa7 | ||
|
|
b692ef4cfb | ||
|
|
e725292ee0 | ||
|
|
84dff75399 | ||
|
|
df12b8a659 | ||
|
|
eedf42b904 | ||
|
|
e7ed254d9d | ||
|
|
dfa29bbb7c | ||
|
|
5a06888cc7 | ||
|
|
a9e2168f1d | ||
|
|
eec745c861 | ||
|
|
4cc283d004 | ||
|
|
bc508ff9e6 | ||
|
|
ff72fc4804 | ||
|
|
78399503c5 | ||
|
|
216fd7ddc4 | ||
|
|
688693d2fb | ||
|
|
15b5e93563 | ||
|
|
1bbcc452ae | ||
|
|
1abe00d0b2 | ||
|
|
c8cf8094c3 | ||
|
|
477690edde | ||
|
|
58466f2ab7 | ||
|
|
bb6f51eb43 | ||
|
|
48987c38e2 | ||
|
|
abf9e96d3d | ||
|
|
740f0f0961 | ||
|
|
abb00251c0 | ||
|
|
3335b3d651 | ||
|
|
60de9dddb1 | ||
|
|
a29ee840f2 |
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -2,3 +2,4 @@
|
||||
*.{cmd,[cC][mM][dD]} text eol=crlf
|
||||
*.{bat,[bB][aA][tT]} text eol=crlf
|
||||
*.{sh,[sS][hH]} text eol=lf
|
||||
meshtastic/protobuf/* linguist-generated=true
|
||||
|
||||
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 |
1
.github/workflows/release.yml
vendored
1
.github/workflows/release.yml
vendored
@@ -52,6 +52,7 @@ jobs:
|
||||
prerelease: true
|
||||
release_name: Meshtastic Python ${{ steps.get_version.outputs.version }}
|
||||
tag_name: ${{ steps.get_version.outputs.version }}
|
||||
commitish: ${{ steps.commit_updated.outputs.sha }}
|
||||
body: |
|
||||
Autogenerated by github action, developer should edit as required before publishing...
|
||||
env:
|
||||
|
||||
17
.vscode/launch.json
vendored
17
.vscode/launch.json
vendored
@@ -245,6 +245,23 @@
|
||||
"module": "meshtastic",
|
||||
"justMyCode": true,
|
||||
"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"]
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
|
||||
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)
|
||||

|
||||
@@ -7,17 +13,20 @@
|
||||
[](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
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
**[Getting Started Guide](https://meshtastic.org/docs/software/python/cli/installation)**
|
||||
|
||||
(Documentation/API Reference is currently offline)
|
||||
|
||||
## 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.
|
||||
|
||||
@@ -22,6 +22,7 @@ OUTDIR=${TMPDIR}/out
|
||||
PYIDIR=${TMPDIR}/out
|
||||
mkdir -p "${OUTDIR}" "${INDIR}" "${PYIDIR}"
|
||||
cp ./protobufs/meshtastic/*.proto "${INDIR}"
|
||||
cp ./protobufs/nanopb.proto "${INDIR}"
|
||||
|
||||
# OS-X sed is apparently a little different and expects an arg for -i
|
||||
if [[ $OSTYPE == 'darwin'* ]]; then
|
||||
@@ -36,6 +37,8 @@ $SEDCMD 's/^package meshtastic;/package meshtastic.protobuf;/' "${INDIR}/"*.prot
|
||||
# fix the imports to match
|
||||
$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
|
||||
./nanopb-0.4.8/generator-bin/protoc -I=$TMPDIR/in --python_out "${OUTDIR}" "--mypy_out=${PYIDIR}" $INDIR/*.proto
|
||||
|
||||
|
||||
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()
|
||||
@@ -2,41 +2,44 @@
|
||||
# A library for the Meshtastic Client API
|
||||
|
||||
Primary interfaces: SerialInterface, TCPInterface, BLEInterface
|
||||
|
||||
Install with pip: "[pip3 install meshtastic](https://pypi.org/project/meshtastic/)"
|
||||
|
||||
Source code on [github](https://github.com/meshtastic/python)
|
||||
|
||||
notable properties of interface classes:
|
||||
|
||||
- nodes - The database of received nodes. Includes always up-to-date location and username information for each
|
||||
- `nodes` - The database of received nodes. Includes always up-to-date location and username information for each
|
||||
node in the mesh. This is a read-only datastructure.
|
||||
- nodesByNum - like "nodes" but keyed by nodeNum instead of nodeId
|
||||
- myInfo & metadata - Contain read-only information about the local radio device (software version, hardware version, etc)
|
||||
- localNode - Pointer to a node object for the local node
|
||||
- `nodesByNum` - like "nodes" but keyed by nodeNum instead of nodeId. As such, includes "unknown" nodes which haven't seen a User packet yet
|
||||
- `myInfo` & `metadata` - Contain read-only information about the local radio device (software version, hardware version, etc)
|
||||
- `localNode` - Pointer to a node object for the local node
|
||||
|
||||
notable properties of nodes:
|
||||
- localConfig - Current radio settings, can be written to the radio with the `writeConfig` method.
|
||||
- moduleConfig - Current module settings, can be written to the radio with the `writeConfig` method.
|
||||
- channels - The node's channels, keyed by index.
|
||||
|
||||
- `localConfig` - Current radio settings, can be written to the radio with the `writeConfig` method.
|
||||
- `moduleConfig` - Current module settings, can be written to the radio with the `writeConfig` method.
|
||||
- `channels` - The node's channels, keyed by index.
|
||||
|
||||
# Published PubSub topics
|
||||
|
||||
We use a [publish-subscribe](https://pypubsub.readthedocs.io/en/v4.0.3/) model to communicate asynchronous events. Available
|
||||
topics:
|
||||
|
||||
- meshtastic.connection.established - published once we've successfully connected to the radio and downloaded the node DB
|
||||
- meshtastic.connection.lost - published once we've lost our link to the radio
|
||||
- meshtastic.receive.text(packet) - delivers a received packet as a dictionary, if you only care about a particular
|
||||
- `meshtastic.connection.established` - published once we've successfully connected to the radio and downloaded the node DB
|
||||
- `meshtastic.connection.lost` - published once we've lost our link to the radio
|
||||
- `meshtastic.receive.text(packet)` - delivers a received packet as a dictionary, if you only care about a particular
|
||||
type of packet, you should subscribe to the full topic name. If you want to see all packets, simply subscribe to "meshtastic.receive".
|
||||
- meshtastic.receive.position(packet)
|
||||
- meshtastic.receive.user(packet)
|
||||
- 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.log.line(line) - a raw unparsed log line from the radio
|
||||
- `meshtastic.receive.position(packet)`
|
||||
- `meshtastic.receive.user(packet)`
|
||||
- `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.log.line(line)` - a raw unparsed log line 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
|
||||
that publish will be the packet. Text or binary data packets (from sendData or sendText) will both arrive this way. If you print packet
|
||||
you'll see the fields in the dictionary. decoded.data.payload will contain the raw bytes that were sent. If the packet was sent with
|
||||
sendText, decoded.data.text will **also** be populated with the decoded string. For ASCII these two strings will be the same, but 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
|
||||
you'll see the fields in the dictionary. `decoded.data.payload` will contain the raw bytes that were sent. If the packet was sent with
|
||||
`sendText`, `decoded.data.text` will **also** be populated with the decoded string. For ASCII these two strings will be the same, but for
|
||||
unicode scripts they can be different.
|
||||
|
||||
# Example Usage
|
||||
@@ -77,7 +80,6 @@ from typing import *
|
||||
|
||||
import google.protobuf.json_format
|
||||
import serial # type: ignore[import-untyped]
|
||||
from dotmap import DotMap # type: ignore[import-untyped]
|
||||
from google.protobuf.json_format import MessageToJson
|
||||
from pubsub import pub # type: ignore[import-untyped]
|
||||
from tabulate import tabulate
|
||||
@@ -108,13 +110,13 @@ from . import (
|
||||
LOCAL_ADDR = "^local"
|
||||
"""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"""
|
||||
|
||||
BROADCAST_ADDR = "^all"
|
||||
"""A special ID that means broadcast"""
|
||||
|
||||
OUR_APP_VERSION = 20300
|
||||
OUR_APP_VERSION: int = 20300
|
||||
"""The numeric buildnumber (shared with android apps) specifying the
|
||||
level of device code we are guaranteed to understand
|
||||
|
||||
@@ -131,7 +133,9 @@ class ResponseHandler(NamedTuple):
|
||||
"""A pending response callback, waiting for a response to one of our messages"""
|
||||
|
||||
# requestId: int - used only as a key
|
||||
#: a callable to call when a response is received
|
||||
callback: Callable
|
||||
#: Whether ACKs and NAKs should be passed to this handler
|
||||
ackPermitted: bool = False
|
||||
# FIXME, add timestamp and age out old requests
|
||||
|
||||
@@ -139,11 +143,11 @@ class ResponseHandler(NamedTuple):
|
||||
class KnownProtocol(NamedTuple):
|
||||
"""Used to automatically decode known protocol payloads"""
|
||||
|
||||
#: A descriptive name (e.g. "text", "user", "admin")
|
||||
name: str
|
||||
# portnum: int, now a key
|
||||
# If set, will be called to prase as a protocol buffer
|
||||
#: If set, will be called to parse as a protocol buffer
|
||||
protobufFactory: Optional[Callable] = None
|
||||
# If set, invoked as onReceive(interface, packet)
|
||||
#: If set, invoked as onReceive(interface, packet)
|
||||
onReceive: Optional[Callable] = None
|
||||
|
||||
|
||||
@@ -191,6 +195,34 @@ def _onNodeInfoReceive(iface, asDict):
|
||||
iface.nodes[p["id"]] = n
|
||||
_receiveInfoUpdate(iface, asDict)
|
||||
|
||||
def _onTelemetryReceive(iface, asDict):
|
||||
"""Automatically update device metrics on received packets"""
|
||||
logging.debug(f"in _onTelemetryReceive() asDict:{asDict}")
|
||||
if "from" not in asDict:
|
||||
return
|
||||
|
||||
toUpdate = None
|
||||
|
||||
telemetry = asDict.get("decoded", {}).get("telemetry", {})
|
||||
node = iface._getOrCreateByNum(asDict["from"])
|
||||
if "deviceMetrics" in telemetry:
|
||||
toUpdate = "deviceMetrics"
|
||||
elif "environmentMetrics" in telemetry:
|
||||
toUpdate = "environmentMetrics"
|
||||
elif "airQualityMetrics" in telemetry:
|
||||
toUpdate = "airQualityMetrics"
|
||||
elif "powerMetrics" in telemetry:
|
||||
toUpdate = "powerMetrics"
|
||||
elif "localStats" in telemetry:
|
||||
toUpdate = "localStats"
|
||||
else:
|
||||
return
|
||||
|
||||
updateObj = telemetry.get(toUpdate)
|
||||
newMetrics = node.get(toUpdate, {})
|
||||
newMetrics.update(updateObj)
|
||||
logging.debug(f"updating {toUpdate} metrics for {asDict['from']} to {newMetrics}")
|
||||
node[toUpdate] = newMetrics
|
||||
|
||||
def _receiveInfoUpdate(iface, asDict):
|
||||
if "from" in asDict:
|
||||
@@ -199,6 +231,12 @@ def _receiveInfoUpdate(iface, asDict):
|
||||
iface._getOrCreateByNum(asDict["from"])["snr"] = asDict.get("rxSnr")
|
||||
iface._getOrCreateByNum(asDict["from"])["hopLimit"] = asDict.get("hopLimit")
|
||||
|
||||
def _onAdminReceive(iface, asDict):
|
||||
"""Special auto parsing for received messages"""
|
||||
logging.debug(f"in _onAdminReceive() asDict:{asDict}")
|
||||
if "decoded" in asDict and "from" in asDict and "admin" in asDict["decoded"]:
|
||||
adminMessage = asDict["decoded"]["admin"]["raw"]
|
||||
iface._getOrCreateByNum(asDict["from"])["adminSessionPassKey"] = adminMessage.session_passkey
|
||||
|
||||
"""Well known message payloads can register decoders for automatic protobuf parsing"""
|
||||
protocols = {
|
||||
@@ -218,10 +256,12 @@ protocols = {
|
||||
portnums_pb2.PortNum.NODEINFO_APP: KnownProtocol(
|
||||
"user", mesh_pb2.User, _onNodeInfoReceive
|
||||
),
|
||||
portnums_pb2.PortNum.ADMIN_APP: KnownProtocol("admin", admin_pb2.AdminMessage),
|
||||
portnums_pb2.PortNum.ADMIN_APP: KnownProtocol(
|
||||
"admin", admin_pb2.AdminMessage, _onAdminReceive
|
||||
),
|
||||
portnums_pb2.PortNum.ROUTING_APP: KnownProtocol("routing", mesh_pb2.Routing),
|
||||
portnums_pb2.PortNum.TELEMETRY_APP: KnownProtocol(
|
||||
"telemetry", telemetry_pb2.Telemetry
|
||||
"telemetry", telemetry_pb2.Telemetry, _onTelemetryReceive
|
||||
),
|
||||
portnums_pb2.PortNum.REMOTE_HARDWARE_APP: KnownProtocol(
|
||||
"remotehw", remote_hardware_pb2.HardwareMessage
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@ import atexit
|
||||
import logging
|
||||
import struct
|
||||
import time
|
||||
import io
|
||||
from threading import Thread
|
||||
from typing import List, Optional
|
||||
|
||||
@@ -34,9 +35,9 @@ class BLEInterface(MeshInterface):
|
||||
self,
|
||||
address: Optional[str],
|
||||
noProto: bool = False,
|
||||
debugOut=None,
|
||||
debugOut: Optional[io.TextIOWrapper]=None,
|
||||
noNodes: bool = False,
|
||||
):
|
||||
) -> None:
|
||||
MeshInterface.__init__(
|
||||
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
|
||||
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.
|
||||
Note: this method does not need to be async because it is just setting a bool.
|
||||
"""
|
||||
@@ -150,9 +162,12 @@ class BLEInterface(MeshInterface):
|
||||
)
|
||||
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."
|
||||
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":
|
||||
"Connect to a device by address."
|
||||
@@ -164,12 +179,16 @@ class BLEInterface(MeshInterface):
|
||||
client.discover()
|
||||
return client
|
||||
|
||||
def _receiveFromRadioImpl(self):
|
||||
def _receiveFromRadioImpl(self) -> None:
|
||||
while self._want_receive:
|
||||
if self.should_read:
|
||||
self.should_read = False
|
||||
retries = 0
|
||||
retries: int = 0
|
||||
while self._want_receive:
|
||||
if self.client is None:
|
||||
logging.debug(f"BLE client is None, shutting down")
|
||||
self._want_receive = False
|
||||
continue
|
||||
try:
|
||||
b = bytes(self.client.read_gatt_char(FROMRADIO_UUID))
|
||||
except BleakDBusError as e:
|
||||
@@ -194,8 +213,8 @@ class BLEInterface(MeshInterface):
|
||||
else:
|
||||
time.sleep(0.01)
|
||||
|
||||
def _sendToRadioImpl(self, toRadio):
|
||||
b = toRadio.SerializeToString()
|
||||
def _sendToRadioImpl(self, toRadio) -> None:
|
||||
b: bytes = toRadio.SerializeToString()
|
||||
if b and self.client: # we silently ignore writes while we are shutting down
|
||||
logging.debug(f"TORADIO write: {b.hex()}")
|
||||
try:
|
||||
@@ -211,14 +230,14 @@ class BLEInterface(MeshInterface):
|
||||
time.sleep(0.01)
|
||||
self.should_read = True
|
||||
|
||||
def close(self):
|
||||
def close(self) -> None:
|
||||
try:
|
||||
MeshInterface.close(self)
|
||||
except Exception as e:
|
||||
logging.error(f"Error closing mesh interface: {e}")
|
||||
|
||||
if self._want_receive:
|
||||
self.want_receive = False # Tell the thread we want it to stop
|
||||
self._want_receive = False # Tell the thread we want it to stop
|
||||
if self._receiveThread:
|
||||
self._receiveThread.join(
|
||||
timeout=2
|
||||
@@ -230,12 +249,13 @@ class BLEInterface(MeshInterface):
|
||||
self.client.disconnect()
|
||||
self.client.close()
|
||||
self.client = None
|
||||
self._disconnected() # send the disconnected indicator up to clients
|
||||
|
||||
|
||||
class BLEClient:
|
||||
"""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._eventThread = Thread(
|
||||
target=self._run_event_loop, name="BLEClient", daemon=True
|
||||
|
||||
@@ -1,19 +1,27 @@
|
||||
"""Mesh Interface class
|
||||
"""
|
||||
# pylint: disable=R0917
|
||||
|
||||
import collections
|
||||
import json
|
||||
import logging
|
||||
import math
|
||||
import random
|
||||
import secrets
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
from typing import Any, Callable, Dict, List, Optional, Union
|
||||
|
||||
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 tabulate import tabulate
|
||||
|
||||
@@ -139,19 +147,19 @@ class MeshInterface: # pylint: disable=R0902
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
def __exit__(self, exc_type, exc_value, trace):
|
||||
if exc_type is not None and exc_value is not None:
|
||||
logging.error(
|
||||
f"An exception of type {exc_type} with value {exc_value} has occurred"
|
||||
)
|
||||
if traceback is not None:
|
||||
logging.error(f"Traceback: {traceback}")
|
||||
if trace is not None:
|
||||
logging.error(f"Traceback: {trace}")
|
||||
self.close()
|
||||
|
||||
@staticmethod
|
||||
def _printLogLine(line, interface):
|
||||
"""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
|
||||
if "DEBUG" in line:
|
||||
print_color.print(line, color="cyan", end=None)
|
||||
@@ -214,9 +222,42 @@ class MeshInterface: # pylint: disable=R0902
|
||||
return infos
|
||||
|
||||
def showNodes(
|
||||
self, includeSelf: bool = True
|
||||
self, includeSelf: bool = True, showFields: Optional[List[str]] = None
|
||||
) -> 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]:
|
||||
"""Format a float value with precision."""
|
||||
@@ -238,6 +279,29 @@ class MeshInterface: # pylint: disable=R0902
|
||||
return None # not handling a timestamp from the future
|
||||
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]] = []
|
||||
if self.nodesByNum:
|
||||
logging.debug(f"self.nodes:{self.nodes}")
|
||||
@@ -246,64 +310,60 @@ class MeshInterface: # pylint: disable=R0902
|
||||
continue
|
||||
|
||||
presumptive_id = f"!{node['num']:08x}"
|
||||
row = {
|
||||
"N": 0,
|
||||
"User": f"Meshtastic {presumptive_id[-4:]}",
|
||||
"ID": presumptive_id,
|
||||
}
|
||||
|
||||
user = node.get("user")
|
||||
if user:
|
||||
row.update(
|
||||
{
|
||||
"User": user.get("longName", "N/A"),
|
||||
"AKA": user.get("shortName", "N/A"),
|
||||
"ID": user["id"],
|
||||
"Hardware": user.get("hwModel", "UNSET"),
|
||||
}
|
||||
)
|
||||
|
||||
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"
|
||||
# This allows the user to specify fields that wouldn't otherwise be included.
|
||||
fields = {}
|
||||
for field in showFields:
|
||||
if "." in field:
|
||||
raw_value = getNestedValue(node, field)
|
||||
else:
|
||||
# The "since" column is synthesized, it's not retrieved from the device. Get the
|
||||
# lastHeard value here, and then we'll format it properly below.
|
||||
if field == "since":
|
||||
raw_value = node.get("lastHeard")
|
||||
else:
|
||||
batteryString = str(batteryLevel) + "%"
|
||||
row.update({"Battery": batteryString})
|
||||
row.update(
|
||||
{
|
||||
"Channel util.": formatFloat(
|
||||
metrics.get("channelUtilization"), 2, "%"
|
||||
),
|
||||
"Tx air util.": formatFloat(
|
||||
metrics.get("airUtilTx"), 2, "%"
|
||||
),
|
||||
}
|
||||
)
|
||||
raw_value = node.get(field)
|
||||
|
||||
row.update(
|
||||
{
|
||||
"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")),
|
||||
}
|
||||
)
|
||||
formatted_value: Optional[str] = ""
|
||||
|
||||
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)
|
||||
for i, row in enumerate(rows):
|
||||
@@ -314,19 +374,33 @@ class MeshInterface: # pylint: disable=R0902
|
||||
return table
|
||||
|
||||
def getNode(
|
||||
self, nodeId: str, requestChannels: bool = True
|
||||
self, nodeId: str, requestChannels: bool = True, requestChannelAttempts: int = 3, timeout: int = 300
|
||||
) -> meshtastic.node.Node:
|
||||
"""Return a node object which contains device settings and channel info"""
|
||||
if nodeId in (LOCAL_ADDR, BROADCAST_ADDR):
|
||||
return self.localNode
|
||||
else:
|
||||
n = meshtastic.node.Node(self, nodeId)
|
||||
n = meshtastic.node.Node(self, nodeId, timeout=timeout)
|
||||
# Only request device settings and channel info when necessary
|
||||
if requestChannels:
|
||||
logging.debug("About to requestChannels")
|
||||
n.requestChannels()
|
||||
if not n.waitForConfig():
|
||||
our_exit("Error: Timed out waiting for channels")
|
||||
retries_left = requestChannelAttempts
|
||||
last_index: int = 0
|
||||
while retries_left > 0:
|
||||
retries_left -= 1
|
||||
if not n.waitForConfig():
|
||||
new_index: int = len(n.partialChannels) if n.partialChannels else 0
|
||||
# each time we get a new channel, reset the counter
|
||||
if new_index != last_index:
|
||||
retries_left = requestChannelAttempts - 1
|
||||
if retries_left <= 0:
|
||||
our_exit("Error: Timed out waiting for channels, giving up")
|
||||
print("Timed out trying to retrieve channel info, retrying")
|
||||
n.requestChannels(startingIndex=new_index)
|
||||
last_index = new_index
|
||||
else:
|
||||
break
|
||||
return n
|
||||
|
||||
def sendText(
|
||||
@@ -337,6 +411,7 @@ class MeshInterface: # pylint: disable=R0902
|
||||
wantResponse: bool = False,
|
||||
onResponse: Optional[Callable[[dict], Any]] = None,
|
||||
channelIndex: int = 0,
|
||||
portNum: portnums_pb2.PortNum.ValueType = portnums_pb2.PortNum.TEXT_MESSAGE_APP
|
||||
):
|
||||
"""Send a utf8 string to some other node, if the node has a display it
|
||||
will also be shown on the device.
|
||||
@@ -347,12 +422,12 @@ class MeshInterface: # pylint: disable=R0902
|
||||
Keyword Arguments:
|
||||
destinationId {nodeId or nodeNum} -- where to send this
|
||||
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
|
||||
(with retries and ack/nak provided for delivery)
|
||||
wantResponse -- True if you want the service on the other side to
|
||||
send an application layer response
|
||||
portNum -- the application portnum (similar to IP port numbers)
|
||||
of the destination, see portnums.proto for a list
|
||||
|
||||
Returns the sent packet. The id field will be populated in this packet
|
||||
and can be used to track future message acks/naks.
|
||||
@@ -361,13 +436,47 @@ class MeshInterface: # pylint: disable=R0902
|
||||
return self.sendData(
|
||||
text.encode("utf-8"),
|
||||
destinationId,
|
||||
portNum=portnums_pb2.PortNum.TEXT_MESSAGE_APP,
|
||||
portNum=portNum,
|
||||
wantAck=wantAck,
|
||||
wantResponse=wantResponse,
|
||||
onResponse=onResponse,
|
||||
channelIndex=channelIndex,
|
||||
)
|
||||
|
||||
|
||||
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 sendData(
|
||||
self,
|
||||
data,
|
||||
@@ -379,7 +488,10 @@ class MeshInterface: # pylint: disable=R0902
|
||||
onResponseAckPermitted: bool=False,
|
||||
channelIndex: int=0,
|
||||
hopLimit: Optional[int]=None,
|
||||
):
|
||||
pkiEncrypted: Optional[bool]=False,
|
||||
publicKey: Optional[bytes]=None,
|
||||
priority: mesh_pb2.MeshPacket.Priority.ValueType=mesh_pb2.MeshPacket.Priority.RELIABLE,
|
||||
): # pylint: disable=R0913
|
||||
"""Send a data packet to some other node
|
||||
|
||||
Keyword Arguments:
|
||||
@@ -430,11 +542,13 @@ class MeshInterface: # pylint: disable=R0902
|
||||
meshPacket.decoded.portnum = portNum
|
||||
meshPacket.decoded.want_response = wantResponse
|
||||
meshPacket.id = self._generatePacketId()
|
||||
if priority is not None:
|
||||
meshPacket.priority = priority
|
||||
|
||||
if onResponse is not None:
|
||||
logging.debug(f"Setting a response handler for requestId {meshPacket.id}")
|
||||
self._addResponseHandler(meshPacket.id, onResponse, ackPermitted=onResponseAckPermitted)
|
||||
p = self._sendPacket(meshPacket, destinationId, wantAck=wantAck, hopLimit=hopLimit)
|
||||
p = self._sendPacket(meshPacket, destinationId, wantAck=wantAck, hopLimit=hopLimit, pkiEncrypted=pkiEncrypted, publicKey=publicKey)
|
||||
return p
|
||||
|
||||
def sendPosition(
|
||||
@@ -442,7 +556,6 @@ class MeshInterface: # pylint: disable=R0902
|
||||
latitude: float = 0.0,
|
||||
longitude: float = 0.0,
|
||||
altitude: int = 0,
|
||||
timeSec: int = 0,
|
||||
destinationId: Union[int, str] = BROADCAST_ADDR,
|
||||
wantAck: bool = False,
|
||||
wantResponse: bool = False,
|
||||
@@ -454,8 +567,6 @@ class MeshInterface: # pylint: disable=R0902
|
||||
Also, the device software will notice this packet and use it to automatically
|
||||
set its notion of the local position.
|
||||
|
||||
If timeSec is not specified (recommended), we will use the local machine time.
|
||||
|
||||
Returns the sent packet. The id field will be populated in this packet and
|
||||
can be used to track future message acks/naks.
|
||||
"""
|
||||
@@ -472,11 +583,6 @@ class MeshInterface: # pylint: disable=R0902
|
||||
p.altitude = int(altitude)
|
||||
logging.debug(f"p.altitude:{p.altitude}")
|
||||
|
||||
if timeSec == 0:
|
||||
timeSec = int(time.time()) # returns unix timestamp in seconds
|
||||
p.time = timeSec
|
||||
logging.debug(f"p.time:{p.time}")
|
||||
|
||||
if wantResponse:
|
||||
onResponse = self.onResponsePosition
|
||||
else:
|
||||
@@ -547,17 +653,46 @@ class MeshInterface: # pylint: disable=R0902
|
||||
|
||||
def onResponseTraceRoute(self, p: dict):
|
||||
"""on response for trace route"""
|
||||
UNK_SNR = -128 # Value representing unknown SNR
|
||||
|
||||
routeDiscovery = mesh_pb2.RouteDiscovery()
|
||||
routeDiscovery.ParseFromString(p["decoded"]["payload"])
|
||||
asDict = google.protobuf.json_format.MessageToDict(routeDiscovery)
|
||||
|
||||
print("Route traced:")
|
||||
routeStr = self._nodeNumToId(p["to"]) or f"{p['to']:08x}"
|
||||
if "route" in asDict:
|
||||
for nodeNum in asDict["route"]:
|
||||
routeStr += " --> " + (self._nodeNumToId(nodeNum) or f"{nodeNum:08x}")
|
||||
routeStr += " --> " + (self._nodeNumToId(p["from"]) or f"{p['from']:08x}")
|
||||
print(routeStr)
|
||||
print("Route traced towards destination:")
|
||||
routeStr = self._nodeNumToId(p["to"], False) or f"{p['to']:08x}" # Start with destination of response
|
||||
|
||||
# SNR list should have one more entry than the route, as the final destination adds its SNR also
|
||||
lenTowards = 0 if "route" not in asDict else len(asDict["route"])
|
||||
snrTowardsValid = "snrTowards" in asDict and len(asDict["snrTowards"]) == lenTowards + 1
|
||||
if lenTowards > 0: # Loop through hops in route and add SNR if available
|
||||
for idx, nodeNum in enumerate(asDict["route"]):
|
||||
routeStr += " --> " + (self._nodeNumToId(nodeNum, False) or f"{nodeNum:08x}") \
|
||||
+ " (" + (str(asDict["snrTowards"][idx] / 4) if snrTowardsValid and asDict["snrTowards"][idx] != UNK_SNR else "?") + "dB)"
|
||||
|
||||
# End with origin of response
|
||||
routeStr += " --> " + (self._nodeNumToId(p["from"], False) or f"{p['from']:08x}") \
|
||||
+ " (" + (str(asDict["snrTowards"][-1] / 4) if snrTowardsValid and asDict["snrTowards"][-1] != UNK_SNR else "?") + "dB)"
|
||||
|
||||
print(routeStr) # Print the route towards destination
|
||||
|
||||
# Only if hopStart is set and there is an SNR entry (for the origin) it's valid, even though route might be empty (direct connection)
|
||||
lenBack = 0 if "routeBack" not in asDict else len(asDict["routeBack"])
|
||||
backValid = "hopStart" in p and "snrBack" in asDict and len(asDict["snrBack"]) == lenBack + 1
|
||||
if backValid:
|
||||
print("Route traced back to us:")
|
||||
routeStr = self._nodeNumToId(p["from"], False) or f"{p['from']:08x}" # Start with origin of response
|
||||
|
||||
if lenBack > 0: # Loop through hops in routeBack and add SNR if available
|
||||
for idx, nodeNum in enumerate(asDict["routeBack"]):
|
||||
routeStr += " --> " + (self._nodeNumToId(nodeNum, False) or f"{nodeNum:08x}") \
|
||||
+ " (" + (str(asDict["snrBack"][idx] / 4) if asDict["snrBack"][idx] != UNK_SNR else "?") + "dB)"
|
||||
|
||||
# End with destination of response (us)
|
||||
routeStr += " --> " + (self._nodeNumToId(p["to"], False) or f"{p['to']:08x}") \
|
||||
+ " (" + (str(asDict["snrBack"][-1] / 4) if asDict["snrBack"][-1] != UNK_SNR else "?") + "dB)"
|
||||
|
||||
print(routeStr) # Print the route back to us
|
||||
|
||||
self._acknowledgment.receivedTraceRoute = True
|
||||
|
||||
@@ -566,32 +701,40 @@ class MeshInterface: # pylint: disable=R0902
|
||||
destinationId: Union[int, str] = BROADCAST_ADDR,
|
||||
wantResponse: bool = False,
|
||||
channelIndex: int = 0,
|
||||
telemetryType: str = "device_metrics"
|
||||
):
|
||||
"""Send telemetry and optionally ask for a response"""
|
||||
r = telemetry_pb2.Telemetry()
|
||||
|
||||
if self.nodes is not None:
|
||||
node = next(
|
||||
n for n in self.nodes.values() if n["num"] == self.localNode.nodeNum
|
||||
)
|
||||
if node is not None:
|
||||
metrics = node.get("deviceMetrics")
|
||||
if metrics:
|
||||
batteryLevel = metrics.get("batteryLevel")
|
||||
if batteryLevel is not None:
|
||||
r.device_metrics.battery_level = batteryLevel
|
||||
voltage = metrics.get("voltage")
|
||||
if voltage is not None:
|
||||
r.device_metrics.voltage = voltage
|
||||
channel_utilization = metrics.get("channelUtilization")
|
||||
if channel_utilization is not None:
|
||||
r.device_metrics.channel_utilization = channel_utilization
|
||||
air_util_tx = metrics.get("airUtilTx")
|
||||
if air_util_tx is not None:
|
||||
r.device_metrics.air_util_tx = air_util_tx
|
||||
uptime_seconds = metrics.get("uptimeSeconds")
|
||||
if uptime_seconds is not None:
|
||||
r.device_metrics.uptime_seconds = uptime_seconds
|
||||
if telemetryType == "environment_metrics":
|
||||
r.environment_metrics.CopyFrom(telemetry_pb2.EnvironmentMetrics())
|
||||
elif telemetryType == "air_quality_metrics":
|
||||
r.air_quality_metrics.CopyFrom(telemetry_pb2.AirQualityMetrics())
|
||||
elif telemetryType == "power_metrics":
|
||||
r.power_metrics.CopyFrom(telemetry_pb2.PowerMetrics())
|
||||
elif telemetryType == "local_stats":
|
||||
r.local_stats.CopyFrom(telemetry_pb2.LocalStats())
|
||||
else: # fall through to device metrics
|
||||
if self.nodesByNum is not None:
|
||||
node = self.nodesByNum.get(self.localNode.nodeNum)
|
||||
if node is not None:
|
||||
metrics = node.get("deviceMetrics")
|
||||
if metrics:
|
||||
batteryLevel = metrics.get("batteryLevel")
|
||||
if batteryLevel is not None:
|
||||
r.device_metrics.battery_level = batteryLevel
|
||||
voltage = metrics.get("voltage")
|
||||
if voltage is not None:
|
||||
r.device_metrics.voltage = voltage
|
||||
channel_utilization = metrics.get("channelUtilization")
|
||||
if channel_utilization is not None:
|
||||
r.device_metrics.channel_utilization = channel_utilization
|
||||
air_util_tx = metrics.get("airUtilTx")
|
||||
if air_util_tx is not None:
|
||||
r.device_metrics.air_util_tx = air_util_tx
|
||||
uptime_seconds = metrics.get("uptimeSeconds")
|
||||
if uptime_seconds is not None:
|
||||
r.device_metrics.uptime_seconds = uptime_seconds
|
||||
|
||||
if wantResponse:
|
||||
onResponse = self.onResponseTelemetry
|
||||
@@ -615,22 +758,32 @@ class MeshInterface: # pylint: disable=R0902
|
||||
self._acknowledgment.receivedTelemetry = True
|
||||
telemetry = telemetry_pb2.Telemetry()
|
||||
telemetry.ParseFromString(p["decoded"]["payload"])
|
||||
|
||||
print("Telemetry received:")
|
||||
if telemetry.device_metrics.battery_level is not None:
|
||||
print(f"Battery level: {telemetry.device_metrics.battery_level:.2f}%")
|
||||
if telemetry.device_metrics.voltage is not None:
|
||||
print(f"Voltage: {telemetry.device_metrics.voltage:.2f} V")
|
||||
if telemetry.device_metrics.channel_utilization is not None:
|
||||
print(
|
||||
f"Total channel utilization: {telemetry.device_metrics.channel_utilization:.2f}%"
|
||||
)
|
||||
if telemetry.device_metrics.air_util_tx is not None:
|
||||
print(
|
||||
f"Transmit air utilization: {telemetry.device_metrics.air_util_tx:.2f}%"
|
||||
)
|
||||
if telemetry.device_metrics.uptime_seconds is not None:
|
||||
print(f"Uptime: {telemetry.device_metrics.uptime_seconds} s")
|
||||
# Check if the telemetry message has the device_metrics field
|
||||
# This is the original code that was the default for --request-telemetry and is kept for compatibility
|
||||
if telemetry.HasField("device_metrics"):
|
||||
if telemetry.device_metrics.battery_level is not None:
|
||||
print(f"Battery level: {telemetry.device_metrics.battery_level:.2f}%")
|
||||
if telemetry.device_metrics.voltage is not None:
|
||||
print(f"Voltage: {telemetry.device_metrics.voltage:.2f} V")
|
||||
if telemetry.device_metrics.channel_utilization is not None:
|
||||
print(
|
||||
f"Total channel utilization: {telemetry.device_metrics.channel_utilization:.2f}%"
|
||||
)
|
||||
if telemetry.device_metrics.air_util_tx is not None:
|
||||
print(
|
||||
f"Transmit air utilization: {telemetry.device_metrics.air_util_tx:.2f}%"
|
||||
)
|
||||
if telemetry.device_metrics.uptime_seconds is not None:
|
||||
print(f"Uptime: {telemetry.device_metrics.uptime_seconds} s")
|
||||
else:
|
||||
# this is the new code if --request-telemetry <type> is used.
|
||||
telemetry_dict = google.protobuf.json_format.MessageToDict(telemetry)
|
||||
for key, value in telemetry_dict.items():
|
||||
if key != "time": # protobuf includes a time field that we don't print for device_metrics.
|
||||
print(f"{key}:")
|
||||
for sub_key, sub_value in value.items():
|
||||
print(f" {sub_key}: {sub_value}")
|
||||
|
||||
elif p["decoded"]["portnum"] == "ROUTING_APP":
|
||||
if p["decoded"]["routing"]["errorReason"] == "NO_RESPONSE":
|
||||
@@ -638,6 +791,113 @@ class MeshInterface: # pylint: disable=R0902
|
||||
"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(
|
||||
self,
|
||||
requestId: int,
|
||||
@@ -653,7 +913,9 @@ class MeshInterface: # pylint: disable=R0902
|
||||
meshPacket: mesh_pb2.MeshPacket,
|
||||
destinationId: Union[int,str]=BROADCAST_ADDR,
|
||||
wantAck: bool=False,
|
||||
hopLimit: Optional[int]=None
|
||||
hopLimit: Optional[int]=None,
|
||||
pkiEncrypted: Optional[bool]=False,
|
||||
publicKey: Optional[bytes]=None,
|
||||
):
|
||||
"""Send a MeshPacket to the specified node (or if unspecified, broadcast).
|
||||
You probably don't want this - use sendData instead.
|
||||
@@ -681,8 +943,10 @@ class MeshInterface: # pylint: disable=R0902
|
||||
else:
|
||||
our_exit("Warning: No myInfo found.")
|
||||
# A simple hex style nodeid - we can parse this without needing the DB
|
||||
elif destinationId.startswith("!"):
|
||||
nodeNum = int(destinationId[1:], 16)
|
||||
elif isinstance(destinationId, str) and len(destinationId) >= 8:
|
||||
# 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:
|
||||
if self.nodes:
|
||||
node = self.nodes.get(destinationId)
|
||||
@@ -702,6 +966,12 @@ class MeshInterface: # pylint: disable=R0902
|
||||
loraConfig = getattr(self.localNode.localConfig, "lora")
|
||||
meshPacket.hop_limit = getattr(loraConfig, "hop_limit")
|
||||
|
||||
if pkiEncrypted:
|
||||
meshPacket.pki_encrypted = True
|
||||
|
||||
if publicKey is not None:
|
||||
meshPacket.public_key = publicKey
|
||||
|
||||
# if the user hasn't set an ID for this packet (likely and recommended),
|
||||
# we should pick a new unique ID so the message can be tracked.
|
||||
if meshPacket.id == 0:
|
||||
@@ -710,7 +980,7 @@ class MeshInterface: # pylint: disable=R0902
|
||||
toRadio.packet.CopyFrom(meshPacket)
|
||||
if self.noProto:
|
||||
logging.warning(
|
||||
f"Not sending packet because protocol use is disabled by noProto"
|
||||
"Not sending packet because protocol use is disabled by noProto"
|
||||
)
|
||||
else:
|
||||
logging.debug(f"Sending packet: {stripnl(meshPacket)}")
|
||||
@@ -754,6 +1024,12 @@ class MeshInterface: # pylint: disable=R0902
|
||||
if not success:
|
||||
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]:
|
||||
"""Get info about my node."""
|
||||
if self.myInfo is None or self.nodesByNum is None:
|
||||
@@ -782,6 +1058,13 @@ class MeshInterface: # pylint: disable=R0902
|
||||
return user.get("shortName", None)
|
||||
return None
|
||||
|
||||
def getPublicKey(self):
|
||||
"""Get Public Key"""
|
||||
user = self.getMyUser()
|
||||
if user is not None:
|
||||
return user.get("publicKey", None)
|
||||
return None
|
||||
|
||||
def _waitConnected(self, timeout=30.0):
|
||||
"""Block until the initial node db download is complete, or timeout
|
||||
and raise an exception"""
|
||||
@@ -802,7 +1085,10 @@ class MeshInterface: # pylint: disable=R0902
|
||||
"Not connected yet, can not generate packet"
|
||||
)
|
||||
else:
|
||||
self.currentPacketId = (self.currentPacketId + 1) & 0xFFFFFFFF
|
||||
nextPacketId = (self.currentPacketId + 1) & 0xFFFFFFFF
|
||||
nextPacketId = nextPacketId & 0x3FF # == (0xFFFFFFFF >> 22), masks upper 22 bits
|
||||
randomPart = (random.randint(0, 0x3FFFFF) << 10) & 0xFFFFFFFF # generate number with 10 zeros at end
|
||||
self.currentPacketId = nextPacketId | randomPart # combine
|
||||
return self.currentPacketId
|
||||
|
||||
def _disconnected(self):
|
||||
@@ -812,19 +1098,22 @@ class MeshInterface: # pylint: disable=R0902
|
||||
lambda: pub.sendMessage("meshtastic.connection.lost", interface=self)
|
||||
)
|
||||
|
||||
def sendHeartbeat(self):
|
||||
"""Sends a heartbeat to the radio. Can be used to verify the connection is healthy."""
|
||||
p = mesh_pb2.ToRadio()
|
||||
p.heartbeat.CopyFrom(mesh_pb2.Heartbeat())
|
||||
self._sendToRadio(p)
|
||||
|
||||
def _startHeartbeat(self):
|
||||
"""We need to send a heartbeat message to the device every X seconds"""
|
||||
|
||||
def callback():
|
||||
self.heartbeatTimer = None
|
||||
i = 300
|
||||
logging.debug(f"Sending heartbeat, interval {i} seconds")
|
||||
if i != 0:
|
||||
self.heartbeatTimer = threading.Timer(i, callback)
|
||||
self.heartbeatTimer.start()
|
||||
p = mesh_pb2.ToRadio()
|
||||
p.heartbeat.CopyFrom(mesh_pb2.Heartbeat())
|
||||
self._sendToRadio(p)
|
||||
interval = 300
|
||||
logging.debug(f"Sending heartbeat, interval {interval} seconds")
|
||||
self.heartbeatTimer = threading.Timer(interval, callback)
|
||||
self.heartbeatTimer.start()
|
||||
self.sendHeartbeat()
|
||||
|
||||
callback() # run our periodic callback now, it will make another timer if necessary
|
||||
|
||||
@@ -854,6 +1143,8 @@ class MeshInterface: # pylint: disable=R0902
|
||||
startConfig = mesh_pb2.ToRadio()
|
||||
if self.configId is None or not self.noNodes:
|
||||
self.configId = random.randint(0, 0xFFFFFFFF)
|
||||
if self.configId == NODELESS_WANT_CONFIG_ID:
|
||||
self.configId = self.configId + 1
|
||||
startConfig.want_config_id = self.configId
|
||||
self._sendToRadio(startConfig)
|
||||
|
||||
@@ -878,7 +1169,7 @@ class MeshInterface: # pylint: disable=R0902
|
||||
"""Send a ToRadio protobuf to the device"""
|
||||
if self.noProto:
|
||||
logging.warning(
|
||||
f"Not sending packet because protocol use is disabled by noProto"
|
||||
"Not sending packet because protocol use is disabled by noProto"
|
||||
)
|
||||
else:
|
||||
# logging.debug(f"Sending toRadio: {stripnl(toRadio)}")
|
||||
@@ -964,10 +1255,17 @@ class MeshInterface: # pylint: disable=R0902
|
||||
|
||||
Called by subclasses."""
|
||||
fromRadio = mesh_pb2.FromRadio()
|
||||
fromRadio.ParseFromString(fromRadioBytes)
|
||||
logging.debug(
|
||||
f"in mesh_interface.py _handleFromRadio() fromRadioBytes: {fromRadioBytes}"
|
||||
)
|
||||
try:
|
||||
fromRadio.ParseFromString(fromRadioBytes)
|
||||
except Exception as ex:
|
||||
logging.error(
|
||||
f"Error while parsing FromRadio bytes:{fromRadioBytes} {ex}"
|
||||
)
|
||||
traceback.print_exc()
|
||||
raise ex
|
||||
asDict = google.protobuf.json_format.MessageToDict(fromRadio)
|
||||
logging.debug(f"Received from radio: {fromRadio}")
|
||||
if fromRadio.HasField("my_info"):
|
||||
@@ -975,13 +1273,6 @@ class MeshInterface: # pylint: disable=R0902
|
||||
self.localNode.nodeNum = self.myInfo.my_node_num
|
||||
logging.debug(f"Received myinfo: {stripnl(fromRadio.my_info)}")
|
||||
|
||||
failmsg = None
|
||||
|
||||
if failmsg:
|
||||
self.failure = MeshInterface.MeshInterfaceError(failmsg)
|
||||
self.isConnected.set() # let waitConnected return this exception
|
||||
self.close()
|
||||
|
||||
elif fromRadio.HasField("metadata"):
|
||||
self.metadata = fromRadio.metadata
|
||||
logging.debug(f"Received device metadata: {stripnl(fromRadio.metadata)}")
|
||||
@@ -1063,7 +1354,10 @@ class MeshInterface: # pylint: disable=R0902
|
||||
self.localNode.localConfig.bluetooth.CopyFrom(
|
||||
fromRadio.config.bluetooth
|
||||
)
|
||||
|
||||
elif fromRadio.config.HasField("security"):
|
||||
self.localNode.localConfig.security.CopyFrom(
|
||||
fromRadio.config.security
|
||||
)
|
||||
elif fromRadio.moduleConfig.HasField("mqtt"):
|
||||
self.localNode.moduleConfig.mqtt.CopyFrom(fromRadio.moduleConfig.mqtt)
|
||||
elif fromRadio.moduleConfig.HasField("serial"):
|
||||
@@ -1129,17 +1423,21 @@ class MeshInterface: # pylint: disable=R0902
|
||||
position["longitude"] = float(position["longitudeI"] * Decimal("1e-7"))
|
||||
return position
|
||||
|
||||
def _nodeNumToId(self, num: int) -> Optional[str]:
|
||||
def _nodeNumToId(self, num: int, isDest = True) -> Optional[str]:
|
||||
"""Map a node node number to a node ID
|
||||
|
||||
Arguments:
|
||||
num {int} -- Node number
|
||||
isDest {bool} -- True if the node number is a destination (to show broadcast address or unknown node)
|
||||
|
||||
Returns:
|
||||
string -- Node ID
|
||||
"""
|
||||
if num == BROADCAST_NUM:
|
||||
return BROADCAST_ADDR
|
||||
if isDest:
|
||||
return BROADCAST_ADDR
|
||||
else:
|
||||
return "Unknown"
|
||||
|
||||
try:
|
||||
return self.nodesByNum[num]["user"]["id"] # type: ignore[index]
|
||||
@@ -1212,7 +1510,7 @@ class MeshInterface: # pylint: disable=R0902
|
||||
|
||||
# /add fromId and toId fields based on the node ID
|
||||
try:
|
||||
asDict["fromId"] = self._nodeNumToId(asDict["from"])
|
||||
asDict["fromId"] = self._nodeNumToId(asDict["from"], False)
|
||||
except Exception as ex:
|
||||
logging.warning(f"Not populating fromId {ex}")
|
||||
try:
|
||||
|
||||
@@ -13,6 +13,8 @@ with rather more easily once the code is simplified by this change.
|
||||
|
||||
"""
|
||||
|
||||
from typing import Any, Optional
|
||||
|
||||
def reset():
|
||||
"""
|
||||
Restore the namespace to pristine condition.
|
||||
@@ -33,5 +35,5 @@ args = None
|
||||
parser = None
|
||||
channel_index = None
|
||||
logfile = None
|
||||
tunnelInstance = None
|
||||
tunnelInstance: Optional[Any] = None
|
||||
camel_case = False
|
||||
|
||||
@@ -5,7 +5,7 @@ import base64
|
||||
import logging
|
||||
import time
|
||||
|
||||
from typing import Union
|
||||
from typing import Optional, Union, List
|
||||
|
||||
from meshtastic.protobuf import admin_pb2, apponly_pb2, channel_pb2, localonly_pb2, mesh_pb2, portnums_pb2
|
||||
from meshtastic.util import (
|
||||
@@ -25,15 +25,15 @@ class Node:
|
||||
Includes methods for localConfig, moduleConfig and channels
|
||||
"""
|
||||
|
||||
def __init__(self, iface, nodeNum, noProto=False):
|
||||
def __init__(self, iface, nodeNum, noProto=False, timeout: int = 300):
|
||||
"""Constructor"""
|
||||
self.iface = iface
|
||||
self.nodeNum = nodeNum
|
||||
self.localConfig = localonly_pb2.LocalConfig()
|
||||
self.moduleConfig = localonly_pb2.LocalModuleConfig()
|
||||
self.channels = None
|
||||
self._timeout = Timeout(maxSecs=300)
|
||||
self.partialChannels = None
|
||||
self._timeout = Timeout(maxSecs=timeout)
|
||||
self.partialChannels: Optional[List] = None
|
||||
self.noProto = noProto
|
||||
self.cannedPluginMessage = None
|
||||
self.cannedPluginMessageMessages = None
|
||||
@@ -42,6 +42,15 @@ class Node:
|
||||
|
||||
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 showChannels(self):
|
||||
"""Show human readable description of our channels."""
|
||||
print("Channels:")
|
||||
@@ -77,17 +86,19 @@ class Node:
|
||||
self.channels = channels
|
||||
self._fixupChannels()
|
||||
|
||||
def requestChannels(self):
|
||||
def requestChannels(self, startingIndex: int = 0):
|
||||
"""Send regular MeshPackets to ask channels."""
|
||||
logging.debug(f"requestChannels for nodeNum:{self.nodeNum}")
|
||||
self.channels = None
|
||||
self.partialChannels = [] # We keep our channels in a temp array until finished
|
||||
|
||||
self._requestChannel(0)
|
||||
# only initialize if we're starting out fresh
|
||||
if startingIndex == 0:
|
||||
self.channels = None
|
||||
self.partialChannels = [] # We keep our channels in a temp array until finished
|
||||
self._requestChannel(startingIndex)
|
||||
|
||||
def onResponseRequestSettings(self, p):
|
||||
"""Handle the response packets for requesting settings _requestSettings()"""
|
||||
logging.debug(f"onResponseRequestSetting() p:{p}")
|
||||
config_values = None
|
||||
if "routing" in p["decoded"]:
|
||||
if p["decoded"]["routing"]["errorReason"] != "NONE":
|
||||
print(f'Error on response: {p["decoded"]["routing"]["errorReason"]}')
|
||||
@@ -97,13 +108,16 @@ class Node:
|
||||
print("")
|
||||
adminMessage = p["decoded"]["admin"]
|
||||
if "getConfigResponse" in adminMessage:
|
||||
oneof = "get_config_response"
|
||||
resp = adminMessage["getConfigResponse"]
|
||||
field = list(resp.keys())[0]
|
||||
config_type = self.localConfig.DESCRIPTOR.fields_by_name.get(
|
||||
camel_to_snake(field)
|
||||
)
|
||||
config_values = getattr(self.localConfig, config_type.name)
|
||||
if config_type is not None:
|
||||
config_values = getattr(self.localConfig, config_type.name)
|
||||
elif "getModuleConfigResponse" in adminMessage:
|
||||
oneof = "get_module_config_response"
|
||||
resp = adminMessage["getModuleConfigResponse"]
|
||||
field = list(resp.keys())[0]
|
||||
config_type = self.moduleConfig.DESCRIPTOR.fields_by_name.get(
|
||||
@@ -115,9 +129,10 @@ class Node:
|
||||
"Did not receive a valid response. Make sure to have a shared channel named 'admin'."
|
||||
)
|
||||
return
|
||||
for key, value in resp[field].items():
|
||||
setattr(config_values, camel_to_snake(key), value)
|
||||
print(f"{str(camel_to_snake(field))}:\n{str(config_values)}")
|
||||
if config_values is not None:
|
||||
raw_config = getattr(getattr(adminMessage['raw'], oneof), camel_to_snake(field))
|
||||
config_values.CopyFrom(raw_config)
|
||||
print(f"{str(camel_to_snake(field))}:\n{str(config_values)}")
|
||||
|
||||
def requestConfig(self, configType):
|
||||
"""Request the config from the node via admin message"""
|
||||
@@ -126,16 +141,18 @@ class Node:
|
||||
else:
|
||||
onResponse = self.onResponseRequestSettings
|
||||
print("Requesting current config from remote node (this can take a while).")
|
||||
p = admin_pb2.AdminMessage()
|
||||
if isinstance(configType, int):
|
||||
p.get_config_request = configType
|
||||
|
||||
msgIndex = configType.index
|
||||
if configType.containing_type.name == "LocalConfig":
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.get_config_request = msgIndex
|
||||
self._sendAdmin(p, wantResponse=True, onResponse=onResponse)
|
||||
else:
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.get_module_config_request = msgIndex
|
||||
self._sendAdmin(p, wantResponse=True, onResponse=onResponse)
|
||||
msgIndex = configType.index
|
||||
if configType.containing_type.name == "LocalConfig":
|
||||
p.get_config_request = msgIndex
|
||||
else:
|
||||
p.get_module_config_request = msgIndex
|
||||
|
||||
self._sendAdmin(p, wantResponse=True, onResponse=onResponse)
|
||||
if onResponse:
|
||||
self.iface.waitForAckNak()
|
||||
|
||||
@@ -170,6 +187,8 @@ class Node:
|
||||
p.set_config.lora.CopyFrom(self.localConfig.lora)
|
||||
elif config_name == "bluetooth":
|
||||
p.set_config.bluetooth.CopyFrom(self.localConfig.bluetooth)
|
||||
elif config_name == "security":
|
||||
p.set_config.security.CopyFrom(self.localConfig.security)
|
||||
elif config_name == "mqtt":
|
||||
p.set_module_config.mqtt.CopyFrom(self.moduleConfig.mqtt)
|
||||
elif config_name == "serial":
|
||||
@@ -214,7 +233,7 @@ class Node:
|
||||
|
||||
def writeChannel(self, channelIndex, adminIndex=0):
|
||||
"""Write the current (edited) channel to the device"""
|
||||
|
||||
self.ensureSessionKey()
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_channel.CopyFrom(self.channels[channelIndex])
|
||||
self._sendAdmin(p, adminIndex=adminIndex)
|
||||
@@ -279,9 +298,10 @@ class Node:
|
||||
return c.index
|
||||
return 0
|
||||
|
||||
def setOwner(self, long_name=None, short_name=None, is_licensed=False):
|
||||
def setOwner(self, long_name: Optional[str]=None, short_name: Optional[str]=None, is_licensed: bool=False):
|
||||
"""Set device owner name"""
|
||||
logging.debug(f"in setOwner nodeNum:{self.nodeNum}")
|
||||
self.ensureSessionKey()
|
||||
p = admin_pb2.AdminMessage()
|
||||
|
||||
nChars = 4
|
||||
@@ -326,14 +346,19 @@ class Node:
|
||||
s = s.replace("=", "").replace("+", "-").replace("/", "_")
|
||||
return f"https://meshtastic.org/e/#{s}"
|
||||
|
||||
def setURL(self, url):
|
||||
def setURL(self, url: str, addOnly: bool = False):
|
||||
"""Set mesh network URL"""
|
||||
if self.localConfig is None:
|
||||
our_exit("Warning: No Config has been read")
|
||||
if self.localConfig is None or self.channels is None:
|
||||
our_exit("Warning: config or channels not loaded")
|
||||
|
||||
# URLs are of the form https://meshtastic.org/d/#{base64_channel_set}
|
||||
# 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]
|
||||
|
||||
# We normally strip padding to make for a shorter URL, but the python parser doesn't like
|
||||
@@ -350,23 +375,40 @@ class Node:
|
||||
if len(channelSet.settings) == 0:
|
||||
our_exit("Warning: There were no settings.")
|
||||
|
||||
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
|
||||
if addOnly:
|
||||
# Add new channels with names not already present
|
||||
# Don't change existing channels
|
||||
for chs in channelSet.settings:
|
||||
channelExists = self.getChannelByName(chs.name)
|
||||
if channelExists or chs.name == "":
|
||||
print(f"Ignoring existing or empty channel \"{chs.name}\" from add URL")
|
||||
continue
|
||||
ch = self.getDisabledChannel()
|
||||
if not ch:
|
||||
our_exit("Warning: No free channels were found")
|
||||
ch.settings.CopyFrom(chs)
|
||||
ch.role = channel_pb2.Channel.Role.SECONDARY
|
||||
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.set_config.lora.CopyFrom(channelSet.lora_config)
|
||||
self.ensureSessionKey()
|
||||
self._sendAdmin(p)
|
||||
|
||||
def onResponseRequestRingtone(self, p):
|
||||
@@ -415,7 +457,7 @@ class Node:
|
||||
|
||||
if len(ringtone) > 230:
|
||||
our_exit("Warning: The ringtone must be less than 230 characters.")
|
||||
|
||||
self.ensureSessionKey()
|
||||
# split into chunks
|
||||
chunks = []
|
||||
chunks_size = 230
|
||||
@@ -491,7 +533,7 @@ class Node:
|
||||
|
||||
if len(message) > 200:
|
||||
our_exit("Warning: The canned message must be less than 200 characters.")
|
||||
|
||||
self.ensureSessionKey()
|
||||
# split into chunks
|
||||
chunks = []
|
||||
chunks_size = 200
|
||||
@@ -518,6 +560,7 @@ class Node:
|
||||
def exitSimulator(self):
|
||||
"""Tell a simulator node to exit (this message
|
||||
is ignored for other nodes)"""
|
||||
self.ensureSessionKey()
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.exit_simulator = True
|
||||
logging.debug("in exitSimulator()")
|
||||
@@ -526,6 +569,7 @@ class Node:
|
||||
|
||||
def reboot(self, secs: int = 10):
|
||||
"""Tell the node to reboot."""
|
||||
self.ensureSessionKey()
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.reboot_seconds = secs
|
||||
logging.info(f"Telling node to reboot in {secs} seconds")
|
||||
@@ -539,6 +583,7 @@ class Node:
|
||||
|
||||
def beginSettingsTransaction(self):
|
||||
"""Tell the node to open a transaction to edit settings."""
|
||||
self.ensureSessionKey()
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.begin_edit_settings = True
|
||||
logging.info(f"Telling open a transaction to edit settings")
|
||||
@@ -552,6 +597,7 @@ class Node:
|
||||
|
||||
def commitSettingsTransaction(self):
|
||||
"""Tell the node to commit the open transaction for editing settings."""
|
||||
self.ensureSessionKey()
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.commit_edit_settings = True
|
||||
logging.info(f"Telling node to commit open transaction for editing settings")
|
||||
@@ -565,6 +611,7 @@ class Node:
|
||||
|
||||
def rebootOTA(self, secs: int = 10):
|
||||
"""Tell the node to reboot into factory firmware."""
|
||||
self.ensureSessionKey()
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.reboot_ota_seconds = secs
|
||||
logging.info(f"Telling node to reboot to OTA in {secs} seconds")
|
||||
@@ -578,6 +625,7 @@ class Node:
|
||||
|
||||
def enterDFUMode(self):
|
||||
"""Tell the node to enter DFU mode (NRF52)."""
|
||||
self.ensureSessionKey()
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.enter_dfu_mode_request = True
|
||||
logging.info(f"Telling node to enable DFU mode")
|
||||
@@ -591,6 +639,7 @@ class Node:
|
||||
|
||||
def shutdown(self, secs: int = 10):
|
||||
"""Tell the node to shutdown."""
|
||||
self.ensureSessionKey()
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.shutdown_seconds = secs
|
||||
logging.info(f"Telling node to shutdown in {secs} seconds")
|
||||
@@ -613,11 +662,16 @@ class Node:
|
||||
)
|
||||
self.iface.waitForAckNak()
|
||||
|
||||
def factoryReset(self):
|
||||
def factoryReset(self, full: bool = False):
|
||||
"""Tell the node to factory reset."""
|
||||
self.ensureSessionKey()
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.factory_reset = True
|
||||
logging.info(f"Telling node to factory reset")
|
||||
if full:
|
||||
p.factory_reset_device = True
|
||||
logging.info(f"Telling node to factory reset (full device reset)")
|
||||
else:
|
||||
p.factory_reset_config = True
|
||||
logging.info(f"Telling node to factory reset (config reset)")
|
||||
|
||||
# If sending to a remote node, wait for ACK/NAK
|
||||
if self == self.iface.localNode:
|
||||
@@ -628,6 +682,7 @@ class Node:
|
||||
|
||||
def removeNode(self, nodeId: Union[int, str]):
|
||||
"""Tell the node to remove a specific node by ID"""
|
||||
self.ensureSessionKey()
|
||||
if isinstance(nodeId, str):
|
||||
if nodeId.startswith("!"):
|
||||
nodeId = int(nodeId[1:], 16)
|
||||
@@ -643,8 +698,81 @@ class Node:
|
||||
onResponse = self.onAckNak
|
||||
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):
|
||||
"""Tell the node to reset its list of nodes."""
|
||||
self.ensureSessionKey()
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.nodedb_reset = True
|
||||
logging.info(f"Telling node to reset the NodeDB")
|
||||
@@ -658,9 +786,7 @@ class Node:
|
||||
|
||||
def setFixedPosition(self, lat: Union[int, float], lon: Union[int, float], alt: int):
|
||||
"""Tell the node to set fixed position to the provided value and enable the fixed position setting"""
|
||||
if self != self.iface.localNode:
|
||||
logging.error("Setting position of remote nodes is not supported.")
|
||||
return None
|
||||
self.ensureSessionKey()
|
||||
|
||||
p = mesh_pb2.Position()
|
||||
if isinstance(lat, float) and lat != 0.0:
|
||||
@@ -678,15 +804,40 @@ class Node:
|
||||
|
||||
a = admin_pb2.AdminMessage()
|
||||
a.set_fixed_position.CopyFrom(p)
|
||||
return self._sendAdmin(a)
|
||||
|
||||
if self == self.iface.localNode:
|
||||
onResponse = None
|
||||
else:
|
||||
onResponse = self.onAckNak
|
||||
return self._sendAdmin(a, onResponse=onResponse)
|
||||
|
||||
def removeFixedPosition(self):
|
||||
"""Tell the node to remove the fixed position and set the fixed position setting to false"""
|
||||
self.ensureSessionKey()
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.remove_fixed_position = True
|
||||
logging.info(f"Telling node to remove fixed position")
|
||||
|
||||
return self._sendAdmin(p)
|
||||
if self == self.iface.localNode:
|
||||
onResponse = None
|
||||
else:
|
||||
onResponse = self.onAckNak
|
||||
return self._sendAdmin(p, onResponse=onResponse)
|
||||
|
||||
def setTime(self, timeSec: int = 0):
|
||||
"""Tell the node to set its time to the provided timestamp, or the system's current time if not provided or 0."""
|
||||
self.ensureSessionKey()
|
||||
if timeSec == 0:
|
||||
timeSec = int(time.time())
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_time_only = timeSec
|
||||
logging.info(f"Setting node time to {timeSec}")
|
||||
|
||||
if self == self.iface.localNode:
|
||||
onResponse = None
|
||||
else:
|
||||
onResponse = self.onAckNak
|
||||
return self._sendAdmin(p, onResponse=onResponse)
|
||||
|
||||
def _fixupChannels(self):
|
||||
"""Fixup indexes and add disabled channels as needed"""
|
||||
@@ -831,13 +982,33 @@ class Node:
|
||||
): # unless a special channel index was used, we want to use the admin index
|
||||
adminIndex = self.iface.localNode._getAdminChannelIndex()
|
||||
logging.debug(f"adminIndex:{adminIndex}")
|
||||
|
||||
if isinstance(self.nodeNum, int):
|
||||
nodeid = self.nodeNum
|
||||
else: # assume string starting with !
|
||||
nodeid = int(self.nodeNum[1:],16)
|
||||
if "adminSessionPassKey" in self.iface._getOrCreateByNum(nodeid):
|
||||
p.session_passkey = self.iface._getOrCreateByNum(nodeid).get("adminSessionPassKey")
|
||||
return self.iface.sendData(
|
||||
p,
|
||||
self.nodeNum,
|
||||
portNum=portnums_pb2.PortNum.ADMIN_APP,
|
||||
wantAck=False,
|
||||
wantAck=True,
|
||||
wantResponse=wantResponse,
|
||||
onResponse=onResponse,
|
||||
channelIndex=adminIndex,
|
||||
pkiEncrypted=True,
|
||||
)
|
||||
|
||||
def ensureSessionKey(self):
|
||||
"""If our entry in iface.nodesByNum doesn't already have an adminSessionPassKey, make a request to get one"""
|
||||
if self.noProto:
|
||||
logging.warning(
|
||||
f"Not ensuring session key, because protocol use is disabled by noProto"
|
||||
)
|
||||
else:
|
||||
if isinstance(self.nodeNum, int):
|
||||
nodeid = self.nodeNum
|
||||
else: # assume string starting with !
|
||||
nodeid = int(self.nodeNum[1:],16)
|
||||
if self.iface._getOrCreateByNum(nodeid).get("adminSessionPassKey") is None:
|
||||
self.requestConfig(admin_pb2.AdminMessage.SESSIONKEY_CONFIG)
|
||||
|
||||
25
meshtastic/protobuf/admin_pb2.py
generated
25
meshtastic/protobuf/admin_pb2.py
generated
File diff suppressed because one or more lines are too long
137
meshtastic/protobuf/admin_pb2.pyi
generated
137
meshtastic/protobuf/admin_pb2.pyi
generated
@@ -12,6 +12,7 @@ import google.protobuf.message
|
||||
import meshtastic.protobuf.channel_pb2
|
||||
import meshtastic.protobuf.config_pb2
|
||||
import meshtastic.protobuf.connection_status_pb2
|
||||
import meshtastic.protobuf.device_ui_pb2
|
||||
import meshtastic.protobuf.mesh_pb2
|
||||
import meshtastic.protobuf.module_config_pb2
|
||||
import sys
|
||||
@@ -68,6 +69,18 @@ class AdminMessage(google.protobuf.message.Message):
|
||||
"""
|
||||
TODO: REPLACE
|
||||
"""
|
||||
SECURITY_CONFIG: AdminMessage._ConfigType.ValueType # 7
|
||||
"""
|
||||
TODO: REPLACE
|
||||
"""
|
||||
SESSIONKEY_CONFIG: AdminMessage._ConfigType.ValueType # 8
|
||||
"""
|
||||
Session key config
|
||||
"""
|
||||
DEVICEUI_CONFIG: AdminMessage._ConfigType.ValueType # 9
|
||||
"""
|
||||
device-ui config
|
||||
"""
|
||||
|
||||
class ConfigType(_ConfigType, metaclass=_ConfigTypeEnumTypeWrapper):
|
||||
"""
|
||||
@@ -102,6 +115,18 @@ class AdminMessage(google.protobuf.message.Message):
|
||||
"""
|
||||
TODO: REPLACE
|
||||
"""
|
||||
SECURITY_CONFIG: AdminMessage.ConfigType.ValueType # 7
|
||||
"""
|
||||
TODO: REPLACE
|
||||
"""
|
||||
SESSIONKEY_CONFIG: AdminMessage.ConfigType.ValueType # 8
|
||||
"""
|
||||
Session key config
|
||||
"""
|
||||
DEVICEUI_CONFIG: AdminMessage.ConfigType.ValueType # 9
|
||||
"""
|
||||
device-ui config
|
||||
"""
|
||||
|
||||
class _ModuleConfigType:
|
||||
ValueType = typing.NewType("ValueType", builtins.int)
|
||||
@@ -220,6 +245,32 @@ class AdminMessage(google.protobuf.message.Message):
|
||||
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
|
||||
"""
|
||||
|
||||
SESSION_PASSKEY_FIELD_NUMBER: builtins.int
|
||||
GET_CHANNEL_REQUEST_FIELD_NUMBER: builtins.int
|
||||
GET_CHANNEL_RESPONSE_FIELD_NUMBER: builtins.int
|
||||
GET_OWNER_REQUEST_FIELD_NUMBER: builtins.int
|
||||
@@ -242,6 +293,9 @@ class AdminMessage(google.protobuf.message.Message):
|
||||
ENTER_DFU_MODE_REQUEST_FIELD_NUMBER: builtins.int
|
||||
DELETE_FILE_REQUEST_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
|
||||
SET_OWNER_FIELD_NUMBER: builtins.int
|
||||
SET_CHANNEL_FIELD_NUMBER: builtins.int
|
||||
SET_CONFIG_FIELD_NUMBER: builtins.int
|
||||
@@ -253,14 +307,27 @@ class AdminMessage(google.protobuf.message.Message):
|
||||
REMOVE_FAVORITE_NODE_FIELD_NUMBER: builtins.int
|
||||
SET_FIXED_POSITION_FIELD_NUMBER: builtins.int
|
||||
REMOVE_FIXED_POSITION_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
|
||||
COMMIT_EDIT_SETTINGS_FIELD_NUMBER: builtins.int
|
||||
FACTORY_RESET_DEVICE_FIELD_NUMBER: builtins.int
|
||||
REBOOT_OTA_SECONDS_FIELD_NUMBER: builtins.int
|
||||
EXIT_SIMULATOR_FIELD_NUMBER: builtins.int
|
||||
REBOOT_SECONDS_FIELD_NUMBER: builtins.int
|
||||
SHUTDOWN_SECONDS_FIELD_NUMBER: builtins.int
|
||||
FACTORY_RESET_FIELD_NUMBER: builtins.int
|
||||
FACTORY_RESET_CONFIG_FIELD_NUMBER: builtins.int
|
||||
NODEDB_RESET_FIELD_NUMBER: builtins.int
|
||||
session_passkey: builtins.bytes
|
||||
"""
|
||||
The node generates this key and sends it with any get_x_response packets.
|
||||
The client MUST include the same key with any set_x commands. Key expires after 300 seconds.
|
||||
Prevents replay attacks for admin messages.
|
||||
"""
|
||||
get_channel_request: builtins.int
|
||||
"""
|
||||
Send the specified channel in the response to this message
|
||||
@@ -319,6 +386,18 @@ class AdminMessage(google.protobuf.message.Message):
|
||||
"""
|
||||
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 the Canned Message Module messages text.
|
||||
@@ -343,6 +422,23 @@ class AdminMessage(google.protobuf.message.Message):
|
||||
"""
|
||||
Clear fixed position coordinates and then set position.fixed_position = false
|
||||
"""
|
||||
set_time_only: builtins.int
|
||||
"""
|
||||
Set time only on the node
|
||||
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
|
||||
"""
|
||||
Begins an edit transaction for config, module config, owner, and channel settings changes
|
||||
@@ -352,6 +448,10 @@ class AdminMessage(google.protobuf.message.Message):
|
||||
"""
|
||||
Commits an open transaction for any edits made to config, module config, owner, and channel settings
|
||||
"""
|
||||
factory_reset_device: builtins.int
|
||||
"""
|
||||
Tell the node to factory reset config everything; all device state and configuration will be returned to factory defaults and BLE bonds will be cleared.
|
||||
"""
|
||||
reboot_ota_seconds: builtins.int
|
||||
"""
|
||||
Tell the node to reboot into the OTA Firmware in this many seconds (or <0 to cancel reboot)
|
||||
@@ -370,9 +470,9 @@ class AdminMessage(google.protobuf.message.Message):
|
||||
"""
|
||||
Tell the node to shutdown in this many seconds (or <0 to cancel shutdown)
|
||||
"""
|
||||
factory_reset: builtins.int
|
||||
factory_reset_config: builtins.int
|
||||
"""
|
||||
Tell the node to factory reset, all device settings will be returned to factory defaults.
|
||||
Tell the node to factory reset config; all device state and configuration will be returned to factory defaults; BLE bonds will be preserved.
|
||||
"""
|
||||
nodedb_reset: builtins.int
|
||||
"""
|
||||
@@ -460,9 +560,22 @@ class AdminMessage(google.protobuf.message.Message):
|
||||
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.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
session_passkey: builtins.bytes = ...,
|
||||
get_channel_request: builtins.int = ...,
|
||||
get_channel_response: meshtastic.protobuf.channel_pb2.Channel | None = ...,
|
||||
get_owner_request: builtins.bool = ...,
|
||||
@@ -485,6 +598,9 @@ class AdminMessage(google.protobuf.message.Message):
|
||||
enter_dfu_mode_request: builtins.bool = ...,
|
||||
delete_file_request: builtins.str = ...,
|
||||
set_scale: builtins.int = ...,
|
||||
backup_preferences: global___AdminMessage.BackupLocation.ValueType = ...,
|
||||
restore_preferences: global___AdminMessage.BackupLocation.ValueType = ...,
|
||||
remove_backup_preferences: global___AdminMessage.BackupLocation.ValueType = ...,
|
||||
set_owner: meshtastic.protobuf.mesh_pb2.User | None = ...,
|
||||
set_channel: meshtastic.protobuf.channel_pb2.Channel | None = ...,
|
||||
set_config: meshtastic.protobuf.config_pb2.Config | None = ...,
|
||||
@@ -496,18 +612,25 @@ class AdminMessage(google.protobuf.message.Message):
|
||||
remove_favorite_node: builtins.int = ...,
|
||||
set_fixed_position: meshtastic.protobuf.mesh_pb2.Position | None = ...,
|
||||
remove_fixed_position: builtins.bool = ...,
|
||||
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 = ...,
|
||||
commit_edit_settings: builtins.bool = ...,
|
||||
factory_reset_device: builtins.int = ...,
|
||||
reboot_ota_seconds: builtins.int = ...,
|
||||
exit_simulator: builtins.bool = ...,
|
||||
reboot_seconds: builtins.int = ...,
|
||||
shutdown_seconds: builtins.int = ...,
|
||||
factory_reset: builtins.int = ...,
|
||||
factory_reset_config: builtins.int = ...,
|
||||
nodedb_reset: builtins.int = ...,
|
||||
) -> 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", b"factory_reset", "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", "shutdown_seconds", b"shutdown_seconds"]) -> 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", b"factory_reset", "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", "shutdown_seconds", b"shutdown_seconds"]) -> 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", "begin_edit_settings", "commit_edit_settings", "reboot_ota_seconds", "exit_simulator", "reboot_seconds", "shutdown_seconds", "factory_reset", "nodedb_reset"] | None: ...
|
||||
def HasField(self, field_name: typing.Literal["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", "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", "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["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", "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", "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", "backup_preferences", "restore_preferences", "remove_backup_preferences", "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", "factory_reset_device", "reboot_ota_seconds", "exit_simulator", "reboot_seconds", "shutdown_seconds", "factory_reset_config", "nodedb_reset"] | None: ...
|
||||
|
||||
global___AdminMessage = AdminMessage
|
||||
|
||||
|
||||
32
meshtastic/protobuf/atak_pb2.py
generated
32
meshtastic/protobuf/atak_pb2.py
generated
@@ -13,7 +13,7 @@ _sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1emeshtastic/protobuf/atak.proto\x12\x13meshtastic.protobuf\"\x93\x02\n\tTAKPacket\x12\x15\n\ris_compressed\x18\x01 \x01(\x08\x12-\n\x07\x63ontact\x18\x02 \x01(\x0b\x32\x1c.meshtastic.protobuf.Contact\x12)\n\x05group\x18\x03 \x01(\x0b\x32\x1a.meshtastic.protobuf.Group\x12+\n\x06status\x18\x04 \x01(\x0b\x32\x1b.meshtastic.protobuf.Status\x12\'\n\x03pli\x18\x05 \x01(\x0b\x32\x18.meshtastic.protobuf.PLIH\x00\x12,\n\x04\x63hat\x18\x06 \x01(\x0b\x32\x1c.meshtastic.protobuf.GeoChatH\x00\x42\x11\n\x0fpayload_variant\"\\\n\x07GeoChat\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x0f\n\x02to\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x18\n\x0bto_callsign\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\x05\n\x03_toB\x0e\n\x0c_to_callsign\"_\n\x05Group\x12-\n\x04role\x18\x01 \x01(\x0e\x32\x1f.meshtastic.protobuf.MemberRole\x12\'\n\x04team\x18\x02 \x01(\x0e\x32\x19.meshtastic.protobuf.Team\"\x19\n\x06Status\x12\x0f\n\x07\x62\x61ttery\x18\x01 \x01(\r\"4\n\x07\x43ontact\x12\x10\n\x08\x63\x61llsign\x18\x01 \x01(\t\x12\x17\n\x0f\x64\x65vice_callsign\x18\x02 \x01(\t\"_\n\x03PLI\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\r\n\x05speed\x18\x04 \x01(\r\x12\x0e\n\x06\x63ourse\x18\x05 \x01(\r*\xc0\x01\n\x04Team\x12\x14\n\x10Unspecifed_Color\x10\x00\x12\t\n\x05White\x10\x01\x12\n\n\x06Yellow\x10\x02\x12\n\n\x06Orange\x10\x03\x12\x0b\n\x07Magenta\x10\x04\x12\x07\n\x03Red\x10\x05\x12\n\n\x06Maroon\x10\x06\x12\n\n\x06Purple\x10\x07\x12\r\n\tDark_Blue\x10\x08\x12\x08\n\x04\x42lue\x10\t\x12\x08\n\x04\x43yan\x10\n\x12\x08\n\x04Teal\x10\x0b\x12\t\n\x05Green\x10\x0c\x12\x0e\n\nDark_Green\x10\r\x12\t\n\x05\x42rown\x10\x0e*\x7f\n\nMemberRole\x12\x0e\n\nUnspecifed\x10\x00\x12\x0e\n\nTeamMember\x10\x01\x12\x0c\n\x08TeamLead\x10\x02\x12\x06\n\x02HQ\x10\x03\x12\n\n\x06Sniper\x10\x04\x12\t\n\x05Medic\x10\x05\x12\x13\n\x0f\x46orwardObserver\x10\x06\x12\x07\n\x03RTO\x10\x07\x12\x06\n\x02K9\x10\x08\x42_\n\x13\x63om.geeksville.meshB\nATAKProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1emeshtastic/protobuf/atak.proto\x12\x13meshtastic.protobuf\"\xa5\x02\n\tTAKPacket\x12\x15\n\ris_compressed\x18\x01 \x01(\x08\x12-\n\x07\x63ontact\x18\x02 \x01(\x0b\x32\x1c.meshtastic.protobuf.Contact\x12)\n\x05group\x18\x03 \x01(\x0b\x32\x1a.meshtastic.protobuf.Group\x12+\n\x06status\x18\x04 \x01(\x0b\x32\x1b.meshtastic.protobuf.Status\x12\'\n\x03pli\x18\x05 \x01(\x0b\x32\x18.meshtastic.protobuf.PLIH\x00\x12,\n\x04\x63hat\x18\x06 \x01(\x0b\x32\x1c.meshtastic.protobuf.GeoChatH\x00\x12\x10\n\x06\x64\x65tail\x18\x07 \x01(\x0cH\x00\x42\x11\n\x0fpayload_variant\"\\\n\x07GeoChat\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x0f\n\x02to\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x18\n\x0bto_callsign\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\x05\n\x03_toB\x0e\n\x0c_to_callsign\"_\n\x05Group\x12-\n\x04role\x18\x01 \x01(\x0e\x32\x1f.meshtastic.protobuf.MemberRole\x12\'\n\x04team\x18\x02 \x01(\x0e\x32\x19.meshtastic.protobuf.Team\"\x19\n\x06Status\x12\x0f\n\x07\x62\x61ttery\x18\x01 \x01(\r\"4\n\x07\x43ontact\x12\x10\n\x08\x63\x61llsign\x18\x01 \x01(\t\x12\x17\n\x0f\x64\x65vice_callsign\x18\x02 \x01(\t\"_\n\x03PLI\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\r\n\x05speed\x18\x04 \x01(\r\x12\x0e\n\x06\x63ourse\x18\x05 \x01(\r*\xc0\x01\n\x04Team\x12\x14\n\x10Unspecifed_Color\x10\x00\x12\t\n\x05White\x10\x01\x12\n\n\x06Yellow\x10\x02\x12\n\n\x06Orange\x10\x03\x12\x0b\n\x07Magenta\x10\x04\x12\x07\n\x03Red\x10\x05\x12\n\n\x06Maroon\x10\x06\x12\n\n\x06Purple\x10\x07\x12\r\n\tDark_Blue\x10\x08\x12\x08\n\x04\x42lue\x10\t\x12\x08\n\x04\x43yan\x10\n\x12\x08\n\x04Teal\x10\x0b\x12\t\n\x05Green\x10\x0c\x12\x0e\n\nDark_Green\x10\r\x12\t\n\x05\x42rown\x10\x0e*\x7f\n\nMemberRole\x12\x0e\n\nUnspecifed\x10\x00\x12\x0e\n\nTeamMember\x10\x01\x12\x0c\n\x08TeamLead\x10\x02\x12\x06\n\x02HQ\x10\x03\x12\n\n\x06Sniper\x10\x04\x12\t\n\x05Medic\x10\x05\x12\x13\n\x0f\x46orwardObserver\x10\x06\x12\x07\n\x03RTO\x10\x07\x12\x06\n\x02K9\x10\x08\x42_\n\x13\x63om.geeksville.meshB\nATAKProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
@@ -21,20 +21,20 @@ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.atak_pb
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\nATAKProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
|
||||
_globals['_TEAM']._serialized_start=703
|
||||
_globals['_TEAM']._serialized_end=895
|
||||
_globals['_MEMBERROLE']._serialized_start=897
|
||||
_globals['_MEMBERROLE']._serialized_end=1024
|
||||
_globals['_TEAM']._serialized_start=721
|
||||
_globals['_TEAM']._serialized_end=913
|
||||
_globals['_MEMBERROLE']._serialized_start=915
|
||||
_globals['_MEMBERROLE']._serialized_end=1042
|
||||
_globals['_TAKPACKET']._serialized_start=56
|
||||
_globals['_TAKPACKET']._serialized_end=331
|
||||
_globals['_GEOCHAT']._serialized_start=333
|
||||
_globals['_GEOCHAT']._serialized_end=425
|
||||
_globals['_GROUP']._serialized_start=427
|
||||
_globals['_GROUP']._serialized_end=522
|
||||
_globals['_STATUS']._serialized_start=524
|
||||
_globals['_STATUS']._serialized_end=549
|
||||
_globals['_CONTACT']._serialized_start=551
|
||||
_globals['_CONTACT']._serialized_end=603
|
||||
_globals['_PLI']._serialized_start=605
|
||||
_globals['_PLI']._serialized_end=700
|
||||
_globals['_TAKPACKET']._serialized_end=349
|
||||
_globals['_GEOCHAT']._serialized_start=351
|
||||
_globals['_GEOCHAT']._serialized_end=443
|
||||
_globals['_GROUP']._serialized_start=445
|
||||
_globals['_GROUP']._serialized_end=540
|
||||
_globals['_STATUS']._serialized_start=542
|
||||
_globals['_STATUS']._serialized_end=567
|
||||
_globals['_CONTACT']._serialized_start=569
|
||||
_globals['_CONTACT']._serialized_end=621
|
||||
_globals['_PLI']._serialized_start=623
|
||||
_globals['_PLI']._serialized_end=718
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
||||
13
meshtastic/protobuf/atak_pb2.pyi
generated
13
meshtastic/protobuf/atak_pb2.pyi
generated
@@ -248,10 +248,16 @@ class TAKPacket(google.protobuf.message.Message):
|
||||
STATUS_FIELD_NUMBER: builtins.int
|
||||
PLI_FIELD_NUMBER: builtins.int
|
||||
CHAT_FIELD_NUMBER: builtins.int
|
||||
DETAIL_FIELD_NUMBER: builtins.int
|
||||
is_compressed: builtins.bool
|
||||
"""
|
||||
Are the payloads strings compressed for LoRA transport?
|
||||
"""
|
||||
detail: builtins.bytes
|
||||
"""
|
||||
Generic CoT detail XML
|
||||
May be compressed / truncated by the sender (EUD)
|
||||
"""
|
||||
@property
|
||||
def contact(self) -> global___Contact:
|
||||
"""
|
||||
@@ -291,10 +297,11 @@ class TAKPacket(google.protobuf.message.Message):
|
||||
status: global___Status | None = ...,
|
||||
pli: global___PLI | None = ...,
|
||||
chat: global___GeoChat | None = ...,
|
||||
detail: builtins.bytes = ...,
|
||||
) -> None: ...
|
||||
def HasField(self, field_name: typing.Literal["chat", b"chat", "contact", b"contact", "group", b"group", "payload_variant", b"payload_variant", "pli", b"pli", "status", b"status"]) -> builtins.bool: ...
|
||||
def ClearField(self, field_name: typing.Literal["chat", b"chat", "contact", b"contact", "group", b"group", "is_compressed", b"is_compressed", "payload_variant", b"payload_variant", "pli", b"pli", "status", b"status"]) -> None: ...
|
||||
def WhichOneof(self, oneof_group: typing.Literal["payload_variant", b"payload_variant"]) -> typing.Literal["pli", "chat"] | None: ...
|
||||
def HasField(self, field_name: typing.Literal["chat", b"chat", "contact", b"contact", "detail", b"detail", "group", b"group", "payload_variant", b"payload_variant", "pli", b"pli", "status", b"status"]) -> builtins.bool: ...
|
||||
def ClearField(self, field_name: typing.Literal["chat", b"chat", "contact", b"contact", "detail", b"detail", "group", b"group", "is_compressed", b"is_compressed", "payload_variant", b"payload_variant", "pli", b"pli", "status", b"status"]) -> None: ...
|
||||
def WhichOneof(self, oneof_group: typing.Literal["payload_variant", b"payload_variant"]) -> typing.Literal["pli", "chat", "detail"] | None: ...
|
||||
|
||||
global___TAKPacket = TAKPacket
|
||||
|
||||
|
||||
7
meshtastic/protobuf/clientonly_pb2.py
generated
7
meshtastic/protobuf/clientonly_pb2.py
generated
@@ -12,9 +12,10 @@ _sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n$meshtastic/protobuf/clientonly.proto\x12\x13meshtastic.protobuf\x1a#meshtastic/protobuf/localonly.proto\"\x9f\x02\n\rDeviceProfile\x12\x16\n\tlong_name\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x17\n\nshort_name\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x18\n\x0b\x63hannel_url\x18\x03 \x01(\tH\x02\x88\x01\x01\x12\x35\n\x06\x63onfig\x18\x04 \x01(\x0b\x32 .meshtastic.protobuf.LocalConfigH\x03\x88\x01\x01\x12\x42\n\rmodule_config\x18\x05 \x01(\x0b\x32&.meshtastic.protobuf.LocalModuleConfigH\x04\x88\x01\x01\x42\x0c\n\n_long_nameB\r\n\x0b_short_nameB\x0e\n\x0c_channel_urlB\t\n\x07_configB\x10\n\x0e_module_configBe\n\x13\x63om.geeksville.meshB\x10\x43lientOnlyProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n$meshtastic/protobuf/clientonly.proto\x12\x13meshtastic.protobuf\x1a#meshtastic/protobuf/localonly.proto\x1a\x1emeshtastic/protobuf/mesh.proto\"\xc4\x03\n\rDeviceProfile\x12\x16\n\tlong_name\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x17\n\nshort_name\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x18\n\x0b\x63hannel_url\x18\x03 \x01(\tH\x02\x88\x01\x01\x12\x35\n\x06\x63onfig\x18\x04 \x01(\x0b\x32 .meshtastic.protobuf.LocalConfigH\x03\x88\x01\x01\x12\x42\n\rmodule_config\x18\x05 \x01(\x0b\x32&.meshtastic.protobuf.LocalModuleConfigH\x04\x88\x01\x01\x12:\n\x0e\x66ixed_position\x18\x06 \x01(\x0b\x32\x1d.meshtastic.protobuf.PositionH\x05\x88\x01\x01\x12\x15\n\x08ringtone\x18\x07 \x01(\tH\x06\x88\x01\x01\x12\x1c\n\x0f\x63\x61nned_messages\x18\x08 \x01(\tH\x07\x88\x01\x01\x42\x0c\n\n_long_nameB\r\n\x0b_short_nameB\x0e\n\x0c_channel_urlB\t\n\x07_configB\x10\n\x0e_module_configB\x11\n\x0f_fixed_positionB\x0b\n\t_ringtoneB\x12\n\x10_canned_messagesBe\n\x13\x63om.geeksville.meshB\x10\x43lientOnlyProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
@@ -22,6 +23,6 @@ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.cliento
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\020ClientOnlyProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
|
||||
_globals['_DEVICEPROFILE']._serialized_start=99
|
||||
_globals['_DEVICEPROFILE']._serialized_end=386
|
||||
_globals['_DEVICEPROFILE']._serialized_start=131
|
||||
_globals['_DEVICEPROFILE']._serialized_end=583
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
||||
31
meshtastic/protobuf/clientonly_pb2.pyi
generated
31
meshtastic/protobuf/clientonly_pb2.pyi
generated
@@ -7,6 +7,7 @@ import builtins
|
||||
import google.protobuf.descriptor
|
||||
import google.protobuf.message
|
||||
import meshtastic.protobuf.localonly_pb2
|
||||
import meshtastic.protobuf.mesh_pb2
|
||||
import typing
|
||||
|
||||
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
|
||||
@@ -25,6 +26,9 @@ class DeviceProfile(google.protobuf.message.Message):
|
||||
CHANNEL_URL_FIELD_NUMBER: builtins.int
|
||||
CONFIG_FIELD_NUMBER: builtins.int
|
||||
MODULE_CONFIG_FIELD_NUMBER: builtins.int
|
||||
FIXED_POSITION_FIELD_NUMBER: builtins.int
|
||||
RINGTONE_FIELD_NUMBER: builtins.int
|
||||
CANNED_MESSAGES_FIELD_NUMBER: builtins.int
|
||||
long_name: builtins.str
|
||||
"""
|
||||
Long name for the node
|
||||
@@ -37,6 +41,14 @@ class DeviceProfile(google.protobuf.message.Message):
|
||||
"""
|
||||
The url of the channels from our node
|
||||
"""
|
||||
ringtone: builtins.str
|
||||
"""
|
||||
Ringtone for ExternalNotification
|
||||
"""
|
||||
canned_messages: builtins.str
|
||||
"""
|
||||
Predefined messages for CannedMessage
|
||||
"""
|
||||
@property
|
||||
def config(self) -> meshtastic.protobuf.localonly_pb2.LocalConfig:
|
||||
"""
|
||||
@@ -49,6 +61,12 @@ class DeviceProfile(google.protobuf.message.Message):
|
||||
The ModuleConfig of the node
|
||||
"""
|
||||
|
||||
@property
|
||||
def fixed_position(self) -> meshtastic.protobuf.mesh_pb2.Position:
|
||||
"""
|
||||
Fixed position data
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
@@ -57,18 +75,27 @@ class DeviceProfile(google.protobuf.message.Message):
|
||||
channel_url: builtins.str | None = ...,
|
||||
config: meshtastic.protobuf.localonly_pb2.LocalConfig | None = ...,
|
||||
module_config: meshtastic.protobuf.localonly_pb2.LocalModuleConfig | None = ...,
|
||||
fixed_position: meshtastic.protobuf.mesh_pb2.Position | None = ...,
|
||||
ringtone: builtins.str | None = ...,
|
||||
canned_messages: builtins.str | None = ...,
|
||||
) -> None: ...
|
||||
def HasField(self, field_name: typing.Literal["_channel_url", b"_channel_url", "_config", b"_config", "_long_name", b"_long_name", "_module_config", b"_module_config", "_short_name", b"_short_name", "channel_url", b"channel_url", "config", b"config", "long_name", b"long_name", "module_config", b"module_config", "short_name", b"short_name"]) -> builtins.bool: ...
|
||||
def ClearField(self, field_name: typing.Literal["_channel_url", b"_channel_url", "_config", b"_config", "_long_name", b"_long_name", "_module_config", b"_module_config", "_short_name", b"_short_name", "channel_url", b"channel_url", "config", b"config", "long_name", b"long_name", "module_config", b"module_config", "short_name", b"short_name"]) -> None: ...
|
||||
def HasField(self, field_name: typing.Literal["_canned_messages", b"_canned_messages", "_channel_url", b"_channel_url", "_config", b"_config", "_fixed_position", b"_fixed_position", "_long_name", b"_long_name", "_module_config", b"_module_config", "_ringtone", b"_ringtone", "_short_name", b"_short_name", "canned_messages", b"canned_messages", "channel_url", b"channel_url", "config", b"config", "fixed_position", b"fixed_position", "long_name", b"long_name", "module_config", b"module_config", "ringtone", b"ringtone", "short_name", b"short_name"]) -> builtins.bool: ...
|
||||
def ClearField(self, field_name: typing.Literal["_canned_messages", b"_canned_messages", "_channel_url", b"_channel_url", "_config", b"_config", "_fixed_position", b"_fixed_position", "_long_name", b"_long_name", "_module_config", b"_module_config", "_ringtone", b"_ringtone", "_short_name", b"_short_name", "canned_messages", b"canned_messages", "channel_url", b"channel_url", "config", b"config", "fixed_position", b"fixed_position", "long_name", b"long_name", "module_config", b"module_config", "ringtone", b"ringtone", "short_name", b"short_name"]) -> None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_canned_messages", b"_canned_messages"]) -> typing.Literal["canned_messages"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_channel_url", b"_channel_url"]) -> typing.Literal["channel_url"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_config", b"_config"]) -> typing.Literal["config"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_fixed_position", b"_fixed_position"]) -> typing.Literal["fixed_position"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_long_name", b"_long_name"]) -> typing.Literal["long_name"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_module_config", b"_module_config"]) -> typing.Literal["module_config"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_ringtone", b"_ringtone"]) -> typing.Literal["ringtone"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_short_name", b"_short_name"]) -> typing.Literal["short_name"] | None: ...
|
||||
|
||||
global___DeviceProfile = DeviceProfile
|
||||
|
||||
103
meshtastic/protobuf/config_pb2.py
generated
103
meshtastic/protobuf/config_pb2.py
generated
File diff suppressed because one or more lines are too long
258
meshtastic/protobuf/config_pb2.pyi
generated
258
meshtastic/protobuf/config_pb2.pyi
generated
@@ -9,6 +9,7 @@ import google.protobuf.descriptor
|
||||
import google.protobuf.internal.containers
|
||||
import google.protobuf.internal.enum_type_wrapper
|
||||
import google.protobuf.message
|
||||
import meshtastic.protobuf.device_ui_pb2
|
||||
import sys
|
||||
import typing
|
||||
|
||||
@@ -107,6 +108,14 @@ class Config(google.protobuf.message.Message):
|
||||
and automatic TAK PLI (position location information) broadcasts.
|
||||
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):
|
||||
"""
|
||||
@@ -183,6 +192,14 @@ class Config(google.protobuf.message.Message):
|
||||
and automatic TAK PLI (position location information) broadcasts.
|
||||
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:
|
||||
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,
|
||||
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):
|
||||
"""
|
||||
@@ -236,10 +262,18 @@ class Config(google.protobuf.message.Message):
|
||||
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)
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
|
||||
ROLE_FIELD_NUMBER: builtins.int
|
||||
SERIAL_ENABLED_FIELD_NUMBER: builtins.int
|
||||
DEBUG_LOG_ENABLED_FIELD_NUMBER: builtins.int
|
||||
BUTTON_GPIO_FIELD_NUMBER: builtins.int
|
||||
BUZZER_GPIO_FIELD_NUMBER: builtins.int
|
||||
REBROADCAST_MODE_FIELD_NUMBER: builtins.int
|
||||
@@ -256,11 +290,7 @@ class Config(google.protobuf.message.Message):
|
||||
serial_enabled: builtins.bool
|
||||
"""
|
||||
Disabling this will disable the SerialConsole by not initilizing the StreamAPI
|
||||
"""
|
||||
debug_log_enabled: builtins.bool
|
||||
"""
|
||||
By default we turn off logging as soon as an API client connects (to keep shared serial link quiet).
|
||||
Set this to true to leave the debug log outputting even when API is active.
|
||||
Moved to SecurityConfig
|
||||
"""
|
||||
button_gpio: builtins.int
|
||||
"""
|
||||
@@ -289,6 +319,7 @@ class Config(google.protobuf.message.Message):
|
||||
"""
|
||||
If true, device is considered to be "managed" by a mesh administrator
|
||||
Clients should then limit available configuration and administrative options inside the user interface
|
||||
Moved to SecurityConfig
|
||||
"""
|
||||
disable_triple_click: builtins.bool
|
||||
"""
|
||||
@@ -307,7 +338,6 @@ class Config(google.protobuf.message.Message):
|
||||
*,
|
||||
role: global___Config.DeviceConfig.Role.ValueType = ...,
|
||||
serial_enabled: builtins.bool = ...,
|
||||
debug_log_enabled: builtins.bool = ...,
|
||||
button_gpio: builtins.int = ...,
|
||||
buzzer_gpio: builtins.int = ...,
|
||||
rebroadcast_mode: global___Config.DeviceConfig.RebroadcastMode.ValueType = ...,
|
||||
@@ -318,7 +348,7 @@ class Config(google.protobuf.message.Message):
|
||||
tzdef: builtins.str = ...,
|
||||
led_heartbeat_disabled: builtins.bool = ...,
|
||||
) -> None: ...
|
||||
def ClearField(self, field_name: typing.Literal["button_gpio", b"button_gpio", "buzzer_gpio", b"buzzer_gpio", "debug_log_enabled", b"debug_log_enabled", "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", "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
|
||||
class PositionConfig(google.protobuf.message.Message):
|
||||
@@ -585,7 +615,7 @@ class Config(google.protobuf.message.Message):
|
||||
POWERMON_ENABLES_FIELD_NUMBER: builtins.int
|
||||
is_power_saving: builtins.bool
|
||||
"""
|
||||
Description: Will sleep everything as much as possible, for the tracker and sensor role this will also include the lora radio.
|
||||
Description: Will sleep everything as much as possible, for the tracker and sensor role this will also include the lora radio.
|
||||
Don't use this setting if you want to use your device with the phone apps or are using a device without a user button.
|
||||
Technical Details: Works for ESP32 devices and NRF52 devices in the Sensor or Tracker roles
|
||||
"""
|
||||
@@ -679,6 +709,35 @@ class Config(google.protobuf.message.Message):
|
||||
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
|
||||
class IpV4Config(google.protobuf.message.Message):
|
||||
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||
@@ -721,6 +780,7 @@ class Config(google.protobuf.message.Message):
|
||||
ADDRESS_MODE_FIELD_NUMBER: builtins.int
|
||||
IPV4_CONFIG_FIELD_NUMBER: builtins.int
|
||||
RSYSLOG_SERVER_FIELD_NUMBER: builtins.int
|
||||
ENABLED_PROTOCOLS_FIELD_NUMBER: builtins.int
|
||||
wifi_enabled: builtins.bool
|
||||
"""
|
||||
Enable WiFi (disables Bluetooth)
|
||||
@@ -736,7 +796,7 @@ class Config(google.protobuf.message.Message):
|
||||
"""
|
||||
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
|
||||
"""
|
||||
@@ -750,6 +810,10 @@ class Config(google.protobuf.message.Message):
|
||||
"""
|
||||
rsyslog Server and Port
|
||||
"""
|
||||
enabled_protocols: builtins.int
|
||||
"""
|
||||
Flags for enabling/disabling network protocols
|
||||
"""
|
||||
@property
|
||||
def ipv4_config(self) -> global___Config.NetworkConfig.IpV4Config:
|
||||
"""
|
||||
@@ -767,9 +831,10 @@ class Config(google.protobuf.message.Message):
|
||||
address_mode: global___Config.NetworkConfig.AddressMode.ValueType = ...,
|
||||
ipv4_config: global___Config.NetworkConfig.IpV4Config | None = ...,
|
||||
rsyslog_server: builtins.str = ...,
|
||||
enabled_protocols: builtins.int = ...,
|
||||
) -> None: ...
|
||||
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", "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
|
||||
class DisplayConfig(google.protobuf.message.Message):
|
||||
@@ -891,20 +956,24 @@ class Config(google.protobuf.message.Message):
|
||||
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
|
||||
OLED_AUTO: Config.DisplayConfig._OledType.ValueType # 0
|
||||
"""
|
||||
Default / Auto
|
||||
Default / Autodetect
|
||||
"""
|
||||
OLED_SSD1306: Config.DisplayConfig._OledType.ValueType # 1
|
||||
"""
|
||||
Default / Auto
|
||||
Default / Autodetect
|
||||
"""
|
||||
OLED_SH1106: Config.DisplayConfig._OledType.ValueType # 2
|
||||
"""
|
||||
Default / Auto
|
||||
Default / Autodetect
|
||||
"""
|
||||
OLED_SH1107: Config.DisplayConfig._OledType.ValueType # 3
|
||||
"""
|
||||
Can not be auto detected but set by proto. Used for 128x128 screens
|
||||
"""
|
||||
OLED_SH1107_128_64: Config.DisplayConfig._OledType.ValueType # 4
|
||||
"""
|
||||
Can not be auto detected but set by proto. Used for 128x64 screens
|
||||
"""
|
||||
|
||||
class OledType(_OledType, metaclass=_OledTypeEnumTypeWrapper):
|
||||
"""
|
||||
@@ -913,20 +982,24 @@ class Config(google.protobuf.message.Message):
|
||||
|
||||
OLED_AUTO: Config.DisplayConfig.OledType.ValueType # 0
|
||||
"""
|
||||
Default / Auto
|
||||
Default / Autodetect
|
||||
"""
|
||||
OLED_SSD1306: Config.DisplayConfig.OledType.ValueType # 1
|
||||
"""
|
||||
Default / Auto
|
||||
Default / Autodetect
|
||||
"""
|
||||
OLED_SH1106: Config.DisplayConfig.OledType.ValueType # 2
|
||||
"""
|
||||
Default / Auto
|
||||
Default / Autodetect
|
||||
"""
|
||||
OLED_SH1107: Config.DisplayConfig.OledType.ValueType # 3
|
||||
"""
|
||||
Can not be auto detected but set by proto. Used for 128x128 screens
|
||||
"""
|
||||
OLED_SH1107_128_64: Config.DisplayConfig.OledType.ValueType # 4
|
||||
"""
|
||||
Can not be auto detected but set by proto. Used for 128x64 screens
|
||||
"""
|
||||
|
||||
class _DisplayMode:
|
||||
ValueType = typing.NewType("ValueType", builtins.int)
|
||||
@@ -1053,6 +1126,7 @@ class Config(google.protobuf.message.Message):
|
||||
HEADING_BOLD_FIELD_NUMBER: builtins.int
|
||||
WAKE_ON_TAP_OR_MOTION_FIELD_NUMBER: builtins.int
|
||||
COMPASS_ORIENTATION_FIELD_NUMBER: builtins.int
|
||||
USE_12H_CLOCK_FIELD_NUMBER: builtins.int
|
||||
screen_on_secs: builtins.int
|
||||
"""
|
||||
Number of seconds the screen stays on after pressing the user button or receiving a message
|
||||
@@ -1100,6 +1174,11 @@ class Config(google.protobuf.message.Message):
|
||||
"""
|
||||
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__(
|
||||
self,
|
||||
*,
|
||||
@@ -1114,8 +1193,9 @@ class Config(google.protobuf.message.Message):
|
||||
heading_bold: builtins.bool = ...,
|
||||
wake_on_tap_or_motion: builtins.bool = ...,
|
||||
compass_orientation: global___Config.DisplayConfig.CompassOrientation.ValueType = ...,
|
||||
use_12h_clock: builtins.bool = ...,
|
||||
) -> 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
|
||||
class LoRaConfig(google.protobuf.message.Message):
|
||||
@@ -1207,6 +1287,18 @@ class Config(google.protobuf.message.Message):
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
class RegionCode(_RegionCode, metaclass=_RegionCodeEnumTypeWrapper): ...
|
||||
UNSET: Config.LoRaConfig.RegionCode.ValueType # 0
|
||||
@@ -1285,6 +1377,18 @@ class Config(google.protobuf.message.Message):
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
class _ModemPreset:
|
||||
ValueType = typing.NewType("ValueType", builtins.int)
|
||||
@@ -1303,6 +1407,7 @@ class Config(google.protobuf.message.Message):
|
||||
VERY_LONG_SLOW: Config.LoRaConfig._ModemPreset.ValueType # 2
|
||||
"""
|
||||
Very Long Range - Slow
|
||||
Deprecated in 2.5: Works only with txco and is unusably slow
|
||||
"""
|
||||
MEDIUM_SLOW: Config.LoRaConfig._ModemPreset.ValueType # 3
|
||||
"""
|
||||
@@ -1324,6 +1429,12 @@ class Config(google.protobuf.message.Message):
|
||||
"""
|
||||
Long Range - Moderately Fast
|
||||
"""
|
||||
SHORT_TURBO: Config.LoRaConfig._ModemPreset.ValueType # 8
|
||||
"""
|
||||
Short Range - Turbo
|
||||
This is the fastest preset and the only one with 500kHz bandwidth.
|
||||
It is not legal to use in all regions due to this wider bandwidth.
|
||||
"""
|
||||
|
||||
class ModemPreset(_ModemPreset, metaclass=_ModemPresetEnumTypeWrapper):
|
||||
"""
|
||||
@@ -1342,6 +1453,7 @@ class Config(google.protobuf.message.Message):
|
||||
VERY_LONG_SLOW: Config.LoRaConfig.ModemPreset.ValueType # 2
|
||||
"""
|
||||
Very Long Range - Slow
|
||||
Deprecated in 2.5: Works only with txco and is unusably slow
|
||||
"""
|
||||
MEDIUM_SLOW: Config.LoRaConfig.ModemPreset.ValueType # 3
|
||||
"""
|
||||
@@ -1363,6 +1475,12 @@ class Config(google.protobuf.message.Message):
|
||||
"""
|
||||
Long Range - Moderately Fast
|
||||
"""
|
||||
SHORT_TURBO: Config.LoRaConfig.ModemPreset.ValueType # 8
|
||||
"""
|
||||
Short Range - Turbo
|
||||
This is the fastest preset and the only one with 500kHz bandwidth.
|
||||
It is not legal to use in all regions due to this wider bandwidth.
|
||||
"""
|
||||
|
||||
USE_PRESET_FIELD_NUMBER: builtins.int
|
||||
MODEM_PRESET_FIELD_NUMBER: builtins.int
|
||||
@@ -1381,6 +1499,7 @@ class Config(google.protobuf.message.Message):
|
||||
PA_FAN_DISABLED_FIELD_NUMBER: builtins.int
|
||||
IGNORE_INCOMING_FIELD_NUMBER: builtins.int
|
||||
IGNORE_MQTT_FIELD_NUMBER: builtins.int
|
||||
CONFIG_OK_TO_MQTT_FIELD_NUMBER: builtins.int
|
||||
use_preset: builtins.bool
|
||||
"""
|
||||
When enabled, the `modem_preset` fields will be adhered to, else the `bandwidth`/`spread_factor`/`coding_rate`
|
||||
@@ -1474,6 +1593,10 @@ class Config(google.protobuf.message.Message):
|
||||
"""
|
||||
If true, the device will not process any packets received via LoRa that passed via MQTT anywhere on the path towards it.
|
||||
"""
|
||||
config_ok_to_mqtt: builtins.bool
|
||||
"""
|
||||
Sets the ok_to_mqtt bit on outgoing packets
|
||||
"""
|
||||
@property
|
||||
def ignore_incoming(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.int]:
|
||||
"""
|
||||
@@ -1502,8 +1625,9 @@ class Config(google.protobuf.message.Message):
|
||||
pa_fan_disabled: builtins.bool = ...,
|
||||
ignore_incoming: collections.abc.Iterable[builtins.int] | None = ...,
|
||||
ignore_mqtt: builtins.bool = ...,
|
||||
config_ok_to_mqtt: builtins.bool = ...,
|
||||
) -> None: ...
|
||||
def ClearField(self, field_name: typing.Literal["bandwidth", b"bandwidth", "channel_num", b"channel_num", "coding_rate", b"coding_rate", "frequency_offset", b"frequency_offset", "hop_limit", b"hop_limit", "ignore_incoming", b"ignore_incoming", "ignore_mqtt", b"ignore_mqtt", "modem_preset", b"modem_preset", "override_duty_cycle", b"override_duty_cycle", "override_frequency", b"override_frequency", "pa_fan_disabled", b"pa_fan_disabled", "region", b"region", "spread_factor", b"spread_factor", "sx126x_rx_boosted_gain", b"sx126x_rx_boosted_gain", "tx_enabled", b"tx_enabled", "tx_power", b"tx_power", "use_preset", b"use_preset"]) -> None: ...
|
||||
def ClearField(self, field_name: typing.Literal["bandwidth", b"bandwidth", "channel_num", b"channel_num", "coding_rate", b"coding_rate", "config_ok_to_mqtt", b"config_ok_to_mqtt", "frequency_offset", b"frequency_offset", "hop_limit", b"hop_limit", "ignore_incoming", b"ignore_incoming", "ignore_mqtt", b"ignore_mqtt", "modem_preset", b"modem_preset", "override_duty_cycle", b"override_duty_cycle", "override_frequency", b"override_frequency", "pa_fan_disabled", b"pa_fan_disabled", "region", b"region", "spread_factor", b"spread_factor", "sx126x_rx_boosted_gain", b"sx126x_rx_boosted_gain", "tx_enabled", b"tx_enabled", "tx_power", b"tx_power", "use_preset", b"use_preset"]) -> None: ...
|
||||
|
||||
@typing.final
|
||||
class BluetoothConfig(google.protobuf.message.Message):
|
||||
@@ -1545,7 +1669,6 @@ class Config(google.protobuf.message.Message):
|
||||
ENABLED_FIELD_NUMBER: builtins.int
|
||||
MODE_FIELD_NUMBER: builtins.int
|
||||
FIXED_PIN_FIELD_NUMBER: builtins.int
|
||||
DEVICE_LOGGING_ENABLED_FIELD_NUMBER: builtins.int
|
||||
enabled: builtins.bool
|
||||
"""
|
||||
Enable Bluetooth on the device
|
||||
@@ -1558,19 +1681,84 @@ class Config(google.protobuf.message.Message):
|
||||
"""
|
||||
Specified PIN for PairingMode.FixedPin
|
||||
"""
|
||||
device_logging_enabled: builtins.bool
|
||||
"""
|
||||
Enables device (serial style logs) over Bluetooth
|
||||
"""
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
enabled: builtins.bool = ...,
|
||||
mode: global___Config.BluetoothConfig.PairingMode.ValueType = ...,
|
||||
fixed_pin: builtins.int = ...,
|
||||
device_logging_enabled: builtins.bool = ...,
|
||||
) -> None: ...
|
||||
def ClearField(self, field_name: typing.Literal["device_logging_enabled", b"device_logging_enabled", "enabled", b"enabled", "fixed_pin", b"fixed_pin", "mode", b"mode"]) -> None: ...
|
||||
def ClearField(self, field_name: typing.Literal["enabled", b"enabled", "fixed_pin", b"fixed_pin", "mode", b"mode"]) -> None: ...
|
||||
|
||||
@typing.final
|
||||
class SecurityConfig(google.protobuf.message.Message):
|
||||
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||
|
||||
PUBLIC_KEY_FIELD_NUMBER: builtins.int
|
||||
PRIVATE_KEY_FIELD_NUMBER: builtins.int
|
||||
ADMIN_KEY_FIELD_NUMBER: builtins.int
|
||||
IS_MANAGED_FIELD_NUMBER: builtins.int
|
||||
SERIAL_ENABLED_FIELD_NUMBER: builtins.int
|
||||
DEBUG_LOG_API_ENABLED_FIELD_NUMBER: builtins.int
|
||||
ADMIN_CHANNEL_ENABLED_FIELD_NUMBER: builtins.int
|
||||
public_key: builtins.bytes
|
||||
"""
|
||||
The public key of the user's device.
|
||||
Sent out to other nodes on the mesh to allow them to compute a shared secret key.
|
||||
"""
|
||||
private_key: builtins.bytes
|
||||
"""
|
||||
The private key of the device.
|
||||
Used to create a shared key with a remote device.
|
||||
"""
|
||||
is_managed: builtins.bool
|
||||
"""
|
||||
If true, device is considered to be "managed" by a mesh administrator via admin messages
|
||||
Device is managed by a mesh administrator.
|
||||
"""
|
||||
serial_enabled: builtins.bool
|
||||
"""
|
||||
Serial Console over the Stream API."
|
||||
"""
|
||||
debug_log_api_enabled: builtins.bool
|
||||
"""
|
||||
By default we turn off logging as soon as an API client connects (to keep shared serial link quiet).
|
||||
Output live debug logging over serial or bluetooth is set to true.
|
||||
"""
|
||||
admin_channel_enabled: builtins.bool
|
||||
"""
|
||||
Allow incoming device control over the insecure legacy admin channel.
|
||||
"""
|
||||
@property
|
||||
def admin_key(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.bytes]:
|
||||
"""
|
||||
The public key authorized to send admin messages to this node.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
public_key: builtins.bytes = ...,
|
||||
private_key: builtins.bytes = ...,
|
||||
admin_key: collections.abc.Iterable[builtins.bytes] | None = ...,
|
||||
is_managed: builtins.bool = ...,
|
||||
serial_enabled: builtins.bool = ...,
|
||||
debug_log_api_enabled: builtins.bool = ...,
|
||||
admin_channel_enabled: builtins.bool = ...,
|
||||
) -> None: ...
|
||||
def ClearField(self, field_name: typing.Literal["admin_channel_enabled", b"admin_channel_enabled", "admin_key", b"admin_key", "debug_log_api_enabled", b"debug_log_api_enabled", "is_managed", b"is_managed", "private_key", b"private_key", "public_key", b"public_key", "serial_enabled", b"serial_enabled"]) -> None: ...
|
||||
|
||||
@typing.final
|
||||
class SessionkeyConfig(google.protobuf.message.Message):
|
||||
"""
|
||||
Blank config request, strictly for getting the session key
|
||||
"""
|
||||
|
||||
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
) -> None: ...
|
||||
|
||||
DEVICE_FIELD_NUMBER: builtins.int
|
||||
POSITION_FIELD_NUMBER: builtins.int
|
||||
@@ -1579,6 +1767,9 @@ class Config(google.protobuf.message.Message):
|
||||
DISPLAY_FIELD_NUMBER: builtins.int
|
||||
LORA_FIELD_NUMBER: builtins.int
|
||||
BLUETOOTH_FIELD_NUMBER: builtins.int
|
||||
SECURITY_FIELD_NUMBER: builtins.int
|
||||
SESSIONKEY_FIELD_NUMBER: builtins.int
|
||||
DEVICE_UI_FIELD_NUMBER: builtins.int
|
||||
@property
|
||||
def device(self) -> global___Config.DeviceConfig: ...
|
||||
@property
|
||||
@@ -1593,6 +1784,12 @@ class Config(google.protobuf.message.Message):
|
||||
def lora(self) -> global___Config.LoRaConfig: ...
|
||||
@property
|
||||
def bluetooth(self) -> global___Config.BluetoothConfig: ...
|
||||
@property
|
||||
def security(self) -> global___Config.SecurityConfig: ...
|
||||
@property
|
||||
def sessionkey(self) -> global___Config.SessionkeyConfig: ...
|
||||
@property
|
||||
def device_ui(self) -> meshtastic.protobuf.device_ui_pb2.DeviceUIConfig: ...
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
@@ -1603,9 +1800,12 @@ class Config(google.protobuf.message.Message):
|
||||
display: global___Config.DisplayConfig | None = ...,
|
||||
lora: global___Config.LoRaConfig | None = ...,
|
||||
bluetooth: global___Config.BluetoothConfig | None = ...,
|
||||
security: global___Config.SecurityConfig | None = ...,
|
||||
sessionkey: global___Config.SessionkeyConfig | None = ...,
|
||||
device_ui: meshtastic.protobuf.device_ui_pb2.DeviceUIConfig | 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"]) -> 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"]) -> None: ...
|
||||
def WhichOneof(self, oneof_group: typing.Literal["payload_variant", b"payload_variant"]) -> typing.Literal["device", "position", "power", "network", "display", "lora", "bluetooth"] | None: ...
|
||||
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", "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", "device_ui"] | None: ...
|
||||
|
||||
global___Config = Config
|
||||
|
||||
38
meshtastic/protobuf/device_ui_pb2.py
generated
Normal file
38
meshtastic/protobuf/device_ui_pb2.py
generated
Normal file
@@ -0,0 +1,38 @@
|
||||
# -*- 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\"\xeb\x03\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\"\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\x05Theme\x12\x08\n\x04\x44\x41RK\x10\x00\x12\t\n\x05LIGHT\x10\x01\x12\x07\n\x03RED\x10\x02*\x9a\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\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['_THEME']._serialized_start=1002
|
||||
_globals['_THEME']._serialized_end=1039
|
||||
_globals['_LANGUAGE']._serialized_start=1042
|
||||
_globals['_LANGUAGE']._serialized_end=1324
|
||||
_globals['_DEVICEUICONFIG']._serialized_start=61
|
||||
_globals['_DEVICEUICONFIG']._serialized_end=552
|
||||
_globals['_NODEFILTER']._serialized_start=555
|
||||
_globals['_NODEFILTER']._serialized_end=722
|
||||
_globals['_NODEHIGHLIGHT']._serialized_start=724
|
||||
_globals['_NODEHIGHLIGHT']._serialized_end=850
|
||||
_globals['_GEOPOINT']._serialized_start=852
|
||||
_globals['_GEOPOINT']._serialized_end=913
|
||||
_globals['_MAP']._serialized_start=915
|
||||
_globals['_MAP']._serialized_end=1000
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
479
meshtastic/protobuf/device_ui_pb2.pyi
generated
Normal file
479
meshtastic/protobuf/device_ui_pb2.pyi
generated
Normal file
@@ -0,0 +1,479 @@
|
||||
"""
|
||||
@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 _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
|
||||
"""
|
||||
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
|
||||
"""
|
||||
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
|
||||
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
|
||||
"""
|
||||
@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 = ...,
|
||||
) -> 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", "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_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
|
||||
41
meshtastic/protobuf/deviceonly_pb2.py
generated
41
meshtastic/protobuf/deviceonly_pb2.py
generated
@@ -12,13 +12,14 @@ _sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
from meshtastic.protobuf import channel_pb2 as meshtastic_dot_protobuf_dot_channel__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 telemetry_pb2 as meshtastic_dot_protobuf_dot_telemetry__pb2
|
||||
import nanopb_pb2 as nanopb__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 nanopb_pb2 as meshtastic_dot_protobuf_dot_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\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\"\xa1\x02\n\x0cNodeInfoLite\x12\x0b\n\x03num\x18\x01 \x01(\r\x12\'\n\x04user\x18\x02 \x01(\x0b\x32\x19.meshtastic.protobuf.User\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\x11\n\thops_away\x18\t \x01(\r\x12\x13\n\x0bis_favorite\x18\n \x01(\x08\"\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\x1emeshtastic/protobuf/mesh.proto\x1a#meshtastic/protobuf/telemetry.proto\x1a meshtastic/protobuf/config.proto\x1a#meshtastic/protobuf/localonly.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\"\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\"\xde\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(\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()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
@@ -26,20 +27,26 @@ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.deviceo
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\nDeviceOnlyZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000\222?\013\302\001\010<vector>'
|
||||
_USERLITE.fields_by_name['macaddr']._options = None
|
||||
_USERLITE.fields_by_name['macaddr']._serialized_options = b'\030\001'
|
||||
_DEVICESTATE.fields_by_name['no_save']._options = None
|
||||
_DEVICESTATE.fields_by_name['no_save']._serialized_options = b'\030\001'
|
||||
_DEVICESTATE.fields_by_name['node_db_lite']._options = None
|
||||
_DEVICESTATE.fields_by_name['node_db_lite']._serialized_options = b'\222?\'\222\001$std::vector<meshtastic_NodeInfoLite>'
|
||||
_globals['_SCREENFONTS']._serialized_start=1570
|
||||
_globals['_SCREENFONTS']._serialized_end=1632
|
||||
_globals['_POSITIONLITE']._serialized_start=217
|
||||
_globals['_POSITIONLITE']._serialized_end=370
|
||||
_globals['_NODEINFOLITE']._serialized_start=373
|
||||
_globals['_NODEINFOLITE']._serialized_end=662
|
||||
_globals['_DEVICESTATE']._serialized_start=665
|
||||
_globals['_DEVICESTATE']._serialized_end=1179
|
||||
_globals['_CHANNELFILE']._serialized_start=1181
|
||||
_globals['_CHANNELFILE']._serialized_end=1259
|
||||
_globals['_OEMSTORE']._serialized_start=1262
|
||||
_globals['_OEMSTORE']._serialized_end=1568
|
||||
_DEVICESTATE.fields_by_name['did_gps_reset']._options = None
|
||||
_DEVICESTATE.fields_by_name['did_gps_reset']._serialized_options = b'\030\001'
|
||||
_NODEDATABASE.fields_by_name['nodes']._options = None
|
||||
_NODEDATABASE.fields_by_name['nodes']._serialized_options = b'\222?\'\222\001$std::vector<meshtastic_NodeInfoLite>'
|
||||
_globals['_POSITIONLITE']._serialized_start=271
|
||||
_globals['_POSITIONLITE']._serialized_end=424
|
||||
_globals['_USERLITE']._serialized_start=427
|
||||
_globals['_USERLITE']._serialized_end=653
|
||||
_globals['_NODEINFOLITE']._serialized_start=656
|
||||
_globals['_NODEINFOLITE']._serialized_end=1006
|
||||
_globals['_DEVICESTATE']._serialized_start=1009
|
||||
_globals['_DEVICESTATE']._serialized_end=1426
|
||||
_globals['_NODEDATABASE']._serialized_start=1428
|
||||
_globals['_NODEDATABASE']._serialized_end=1553
|
||||
_globals['_CHANNELFILE']._serialized_start=1555
|
||||
_globals['_CHANNELFILE']._serialized_end=1633
|
||||
_globals['_BACKUPPREFERENCES']._serialized_start=1636
|
||||
_globals['_BACKUPPREFERENCES']._serialized_end=1898
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
||||
257
meshtastic/protobuf/deviceonly_pb2.pyi
generated
257
meshtastic/protobuf/deviceonly_pb2.pyi
generated
@@ -7,60 +7,16 @@ import builtins
|
||||
import collections.abc
|
||||
import google.protobuf.descriptor
|
||||
import google.protobuf.internal.containers
|
||||
import google.protobuf.internal.enum_type_wrapper
|
||||
import google.protobuf.message
|
||||
import meshtastic.protobuf.channel_pb2
|
||||
import meshtastic.protobuf.config_pb2
|
||||
import meshtastic.protobuf.localonly_pb2
|
||||
import meshtastic.protobuf.mesh_pb2
|
||||
import meshtastic.protobuf.telemetry_pb2
|
||||
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 _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
|
||||
class PositionLite(google.protobuf.message.Message):
|
||||
"""
|
||||
@@ -112,6 +68,67 @@ class PositionLite(google.protobuf.message.Message):
|
||||
|
||||
global___PositionLite = PositionLite
|
||||
|
||||
@typing.final
|
||||
class UserLite(google.protobuf.message.Message):
|
||||
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||
|
||||
MACADDR_FIELD_NUMBER: builtins.int
|
||||
LONG_NAME_FIELD_NUMBER: builtins.int
|
||||
SHORT_NAME_FIELD_NUMBER: builtins.int
|
||||
HW_MODEL_FIELD_NUMBER: builtins.int
|
||||
IS_LICENSED_FIELD_NUMBER: builtins.int
|
||||
ROLE_FIELD_NUMBER: builtins.int
|
||||
PUBLIC_KEY_FIELD_NUMBER: builtins.int
|
||||
macaddr: builtins.bytes
|
||||
"""
|
||||
This is the addr of the radio.
|
||||
"""
|
||||
long_name: builtins.str
|
||||
"""
|
||||
A full name for this user, i.e. "Kevin Hester"
|
||||
"""
|
||||
short_name: builtins.str
|
||||
"""
|
||||
A VERY short name, ideally two characters.
|
||||
Suitable for a tiny OLED screen
|
||||
"""
|
||||
hw_model: meshtastic.protobuf.mesh_pb2.HardwareModel.ValueType
|
||||
"""
|
||||
TBEAM, HELTEC, etc...
|
||||
Starting in 1.2.11 moved to hw_model enum in the NodeInfo object.
|
||||
Apps will still need the string here for older builds
|
||||
(so OTA update can find the right image), but if the enum is available it will be used instead.
|
||||
"""
|
||||
is_licensed: builtins.bool
|
||||
"""
|
||||
In some regions Ham radio operators have different bandwidth limitations than others.
|
||||
If this user is a licensed operator, set this flag.
|
||||
Also, "long_name" should be their licence number.
|
||||
"""
|
||||
role: meshtastic.protobuf.config_pb2.Config.DeviceConfig.Role.ValueType
|
||||
"""
|
||||
Indicates that the user's role in the mesh
|
||||
"""
|
||||
public_key: builtins.bytes
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
macaddr: builtins.bytes = ...,
|
||||
long_name: builtins.str = ...,
|
||||
short_name: builtins.str = ...,
|
||||
hw_model: meshtastic.protobuf.mesh_pb2.HardwareModel.ValueType = ...,
|
||||
is_licensed: builtins.bool = ...,
|
||||
role: meshtastic.protobuf.config_pb2.Config.DeviceConfig.Role.ValueType = ...,
|
||||
public_key: builtins.bytes = ...,
|
||||
) -> 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: ...
|
||||
|
||||
global___UserLite = UserLite
|
||||
|
||||
@typing.final
|
||||
class NodeInfoLite(google.protobuf.message.Message):
|
||||
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||
@@ -126,6 +143,8 @@ class NodeInfoLite(google.protobuf.message.Message):
|
||||
VIA_MQTT_FIELD_NUMBER: builtins.int
|
||||
HOPS_AWAY_FIELD_NUMBER: builtins.int
|
||||
IS_FAVORITE_FIELD_NUMBER: builtins.int
|
||||
IS_IGNORED_FIELD_NUMBER: builtins.int
|
||||
NEXT_HOP_FIELD_NUMBER: builtins.int
|
||||
num: builtins.int
|
||||
"""
|
||||
The node number
|
||||
@@ -149,15 +168,24 @@ class NodeInfoLite(google.protobuf.message.Message):
|
||||
"""
|
||||
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
|
||||
"""
|
||||
True if node is in our favorites list
|
||||
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.
|
||||
"""
|
||||
@property
|
||||
def user(self) -> meshtastic.protobuf.mesh_pb2.User:
|
||||
def user(self) -> global___UserLite:
|
||||
"""
|
||||
The user info for this node
|
||||
"""
|
||||
@@ -179,18 +207,21 @@ class NodeInfoLite(google.protobuf.message.Message):
|
||||
self,
|
||||
*,
|
||||
num: builtins.int = ...,
|
||||
user: meshtastic.protobuf.mesh_pb2.User | None = ...,
|
||||
user: global___UserLite | None = ...,
|
||||
position: global___PositionLite | None = ...,
|
||||
snr: builtins.float = ...,
|
||||
last_heard: builtins.int = ...,
|
||||
device_metrics: meshtastic.protobuf.telemetry_pb2.DeviceMetrics | None = ...,
|
||||
channel: builtins.int = ...,
|
||||
via_mqtt: builtins.bool = ...,
|
||||
hops_away: builtins.int = ...,
|
||||
hops_away: builtins.int | None = ...,
|
||||
is_favorite: builtins.bool = ...,
|
||||
is_ignored: builtins.bool = ...,
|
||||
next_hop: builtins.int = ...,
|
||||
) -> None: ...
|
||||
def HasField(self, field_name: typing.Literal["device_metrics", b"device_metrics", "position", b"position", "user", b"user"]) -> builtins.bool: ...
|
||||
def ClearField(self, field_name: typing.Literal["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 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", "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: ...
|
||||
|
||||
global___NodeInfoLite = NodeInfoLite
|
||||
|
||||
@@ -215,7 +246,6 @@ class DeviceState(google.protobuf.message.Message):
|
||||
DID_GPS_RESET_FIELD_NUMBER: builtins.int
|
||||
RX_WAYPOINT_FIELD_NUMBER: builtins.int
|
||||
NODE_REMOTE_HARDWARE_PINS_FIELD_NUMBER: builtins.int
|
||||
NODE_DB_LITE_FIELD_NUMBER: builtins.int
|
||||
version: builtins.int
|
||||
"""
|
||||
A version integer used to invalidate old save files when we make
|
||||
@@ -230,7 +260,8 @@ class DeviceState(google.protobuf.message.Message):
|
||||
"""
|
||||
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
|
||||
def my_node(self) -> meshtastic.protobuf.mesh_pb2.MyNodeInfo:
|
||||
@@ -272,12 +303,6 @@ class DeviceState(google.protobuf.message.Message):
|
||||
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__(
|
||||
self,
|
||||
*,
|
||||
@@ -290,13 +315,40 @@ class DeviceState(google.protobuf.message.Message):
|
||||
did_gps_reset: builtins.bool = ...,
|
||||
rx_waypoint: meshtastic.protobuf.mesh_pb2.MeshPacket | None = ...,
|
||||
node_remote_hardware_pins: collections.abc.Iterable[meshtastic.protobuf.mesh_pb2.NodeRemoteHardwarePin] | None = ...,
|
||||
node_db_lite: collections.abc.Iterable[global___NodeInfoLite] | 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 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
|
||||
|
||||
@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
|
||||
class ChannelFile(google.protobuf.message.Message):
|
||||
"""
|
||||
@@ -330,71 +382,62 @@ class ChannelFile(google.protobuf.message.Message):
|
||||
global___ChannelFile = ChannelFile
|
||||
|
||||
@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,
|
||||
show a secondary bootup screen with custom logo and text for 2.5 seconds.
|
||||
The on-disk backup of the node's preferences
|
||||
"""
|
||||
|
||||
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||
|
||||
OEM_ICON_WIDTH_FIELD_NUMBER: builtins.int
|
||||
OEM_ICON_HEIGHT_FIELD_NUMBER: builtins.int
|
||||
OEM_ICON_BITS_FIELD_NUMBER: builtins.int
|
||||
OEM_FONT_FIELD_NUMBER: builtins.int
|
||||
OEM_TEXT_FIELD_NUMBER: builtins.int
|
||||
OEM_AES_KEY_FIELD_NUMBER: builtins.int
|
||||
OEM_LOCAL_CONFIG_FIELD_NUMBER: builtins.int
|
||||
OEM_LOCAL_MODULE_CONFIG_FIELD_NUMBER: builtins.int
|
||||
oem_icon_width: builtins.int
|
||||
VERSION_FIELD_NUMBER: builtins.int
|
||||
TIMESTAMP_FIELD_NUMBER: builtins.int
|
||||
CONFIG_FIELD_NUMBER: builtins.int
|
||||
MODULE_CONFIG_FIELD_NUMBER: builtins.int
|
||||
CHANNELS_FIELD_NUMBER: builtins.int
|
||||
OWNER_FIELD_NUMBER: builtins.int
|
||||
version: 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
|
||||
"""
|
||||
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
|
||||
The timestamp of the backup (if node has time)
|
||||
"""
|
||||
@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
|
||||
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__(
|
||||
self,
|
||||
*,
|
||||
oem_icon_width: builtins.int = ...,
|
||||
oem_icon_height: builtins.int = ...,
|
||||
oem_icon_bits: builtins.bytes = ...,
|
||||
oem_font: global___ScreenFonts.ValueType = ...,
|
||||
oem_text: builtins.str = ...,
|
||||
oem_aes_key: builtins.bytes = ...,
|
||||
oem_local_config: meshtastic.protobuf.localonly_pb2.LocalConfig | None = ...,
|
||||
oem_local_module_config: meshtastic.protobuf.localonly_pb2.LocalModuleConfig | None = ...,
|
||||
version: builtins.int = ...,
|
||||
timestamp: builtins.int = ...,
|
||||
config: meshtastic.protobuf.localonly_pb2.LocalConfig | None = ...,
|
||||
module_config: meshtastic.protobuf.localonly_pb2.LocalModuleConfig | None = ...,
|
||||
channels: global___ChannelFile | None = ...,
|
||||
owner: meshtastic.protobuf.mesh_pb2.User | 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 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 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["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
|
||||
8
meshtastic/protobuf/localonly_pb2.py
generated
8
meshtastic/protobuf/localonly_pb2.py
generated
@@ -15,7 +15,7 @@ from meshtastic.protobuf import config_pb2 as meshtastic_dot_protobuf_dot_config
|
||||
from meshtastic.protobuf import module_config_pb2 as meshtastic_dot_protobuf_dot_module__config__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n#meshtastic/protobuf/localonly.proto\x12\x13meshtastic.protobuf\x1a meshtastic/protobuf/config.proto\x1a\'meshtastic/protobuf/module_config.proto\"\xbc\x03\n\x0bLocalConfig\x12\x38\n\x06\x64\x65vice\x18\x01 \x01(\x0b\x32(.meshtastic.protobuf.Config.DeviceConfig\x12<\n\x08position\x18\x02 \x01(\x0b\x32*.meshtastic.protobuf.Config.PositionConfig\x12\x36\n\x05power\x18\x03 \x01(\x0b\x32\'.meshtastic.protobuf.Config.PowerConfig\x12:\n\x07network\x18\x04 \x01(\x0b\x32).meshtastic.protobuf.Config.NetworkConfig\x12:\n\x07\x64isplay\x18\x05 \x01(\x0b\x32).meshtastic.protobuf.Config.DisplayConfig\x12\x34\n\x04lora\x18\x06 \x01(\x0b\x32&.meshtastic.protobuf.Config.LoRaConfig\x12>\n\tbluetooth\x18\x07 \x01(\x0b\x32+.meshtastic.protobuf.Config.BluetoothConfig\x12\x0f\n\x07version\x18\x08 \x01(\r\"\xf0\x07\n\x11LocalModuleConfig\x12:\n\x04mqtt\x18\x01 \x01(\x0b\x32,.meshtastic.protobuf.ModuleConfig.MQTTConfig\x12>\n\x06serial\x18\x02 \x01(\x0b\x32..meshtastic.protobuf.ModuleConfig.SerialConfig\x12[\n\x15\x65xternal_notification\x18\x03 \x01(\x0b\x32<.meshtastic.protobuf.ModuleConfig.ExternalNotificationConfig\x12K\n\rstore_forward\x18\x04 \x01(\x0b\x32\x34.meshtastic.protobuf.ModuleConfig.StoreForwardConfig\x12\x45\n\nrange_test\x18\x05 \x01(\x0b\x32\x31.meshtastic.protobuf.ModuleConfig.RangeTestConfig\x12\x44\n\ttelemetry\x18\x06 \x01(\x0b\x32\x31.meshtastic.protobuf.ModuleConfig.TelemetryConfig\x12M\n\x0e\x63\x61nned_message\x18\x07 \x01(\x0b\x32\x35.meshtastic.protobuf.ModuleConfig.CannedMessageConfig\x12<\n\x05\x61udio\x18\t \x01(\x0b\x32-.meshtastic.protobuf.ModuleConfig.AudioConfig\x12O\n\x0fremote_hardware\x18\n \x01(\x0b\x32\x36.meshtastic.protobuf.ModuleConfig.RemoteHardwareConfig\x12K\n\rneighbor_info\x18\x0b \x01(\x0b\x32\x34.meshtastic.protobuf.ModuleConfig.NeighborInfoConfig\x12Q\n\x10\x61mbient_lighting\x18\x0c \x01(\x0b\x32\x37.meshtastic.protobuf.ModuleConfig.AmbientLightingConfig\x12Q\n\x10\x64\x65tection_sensor\x18\r \x01(\x0b\x32\x37.meshtastic.protobuf.ModuleConfig.DetectionSensorConfig\x12\x46\n\npaxcounter\x18\x0e \x01(\x0b\x32\x32.meshtastic.protobuf.ModuleConfig.PaxcounterConfig\x12\x0f\n\x07version\x18\x08 \x01(\rBd\n\x13\x63om.geeksville.meshB\x0fLocalOnlyProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n#meshtastic/protobuf/localonly.proto\x12\x13meshtastic.protobuf\x1a meshtastic/protobuf/config.proto\x1a\'meshtastic/protobuf/module_config.proto\"\xfa\x03\n\x0bLocalConfig\x12\x38\n\x06\x64\x65vice\x18\x01 \x01(\x0b\x32(.meshtastic.protobuf.Config.DeviceConfig\x12<\n\x08position\x18\x02 \x01(\x0b\x32*.meshtastic.protobuf.Config.PositionConfig\x12\x36\n\x05power\x18\x03 \x01(\x0b\x32\'.meshtastic.protobuf.Config.PowerConfig\x12:\n\x07network\x18\x04 \x01(\x0b\x32).meshtastic.protobuf.Config.NetworkConfig\x12:\n\x07\x64isplay\x18\x05 \x01(\x0b\x32).meshtastic.protobuf.Config.DisplayConfig\x12\x34\n\x04lora\x18\x06 \x01(\x0b\x32&.meshtastic.protobuf.Config.LoRaConfig\x12>\n\tbluetooth\x18\x07 \x01(\x0b\x32+.meshtastic.protobuf.Config.BluetoothConfig\x12\x0f\n\x07version\x18\x08 \x01(\r\x12<\n\x08security\x18\t \x01(\x0b\x32*.meshtastic.protobuf.Config.SecurityConfig\"\xf0\x07\n\x11LocalModuleConfig\x12:\n\x04mqtt\x18\x01 \x01(\x0b\x32,.meshtastic.protobuf.ModuleConfig.MQTTConfig\x12>\n\x06serial\x18\x02 \x01(\x0b\x32..meshtastic.protobuf.ModuleConfig.SerialConfig\x12[\n\x15\x65xternal_notification\x18\x03 \x01(\x0b\x32<.meshtastic.protobuf.ModuleConfig.ExternalNotificationConfig\x12K\n\rstore_forward\x18\x04 \x01(\x0b\x32\x34.meshtastic.protobuf.ModuleConfig.StoreForwardConfig\x12\x45\n\nrange_test\x18\x05 \x01(\x0b\x32\x31.meshtastic.protobuf.ModuleConfig.RangeTestConfig\x12\x44\n\ttelemetry\x18\x06 \x01(\x0b\x32\x31.meshtastic.protobuf.ModuleConfig.TelemetryConfig\x12M\n\x0e\x63\x61nned_message\x18\x07 \x01(\x0b\x32\x35.meshtastic.protobuf.ModuleConfig.CannedMessageConfig\x12<\n\x05\x61udio\x18\t \x01(\x0b\x32-.meshtastic.protobuf.ModuleConfig.AudioConfig\x12O\n\x0fremote_hardware\x18\n \x01(\x0b\x32\x36.meshtastic.protobuf.ModuleConfig.RemoteHardwareConfig\x12K\n\rneighbor_info\x18\x0b \x01(\x0b\x32\x34.meshtastic.protobuf.ModuleConfig.NeighborInfoConfig\x12Q\n\x10\x61mbient_lighting\x18\x0c \x01(\x0b\x32\x37.meshtastic.protobuf.ModuleConfig.AmbientLightingConfig\x12Q\n\x10\x64\x65tection_sensor\x18\r \x01(\x0b\x32\x37.meshtastic.protobuf.ModuleConfig.DetectionSensorConfig\x12\x46\n\npaxcounter\x18\x0e \x01(\x0b\x32\x32.meshtastic.protobuf.ModuleConfig.PaxcounterConfig\x12\x0f\n\x07version\x18\x08 \x01(\rBd\n\x13\x63om.geeksville.meshB\x0fLocalOnlyProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
@@ -24,7 +24,7 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\017LocalOnlyProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
|
||||
_globals['_LOCALCONFIG']._serialized_start=136
|
||||
_globals['_LOCALCONFIG']._serialized_end=580
|
||||
_globals['_LOCALMODULECONFIG']._serialized_start=583
|
||||
_globals['_LOCALMODULECONFIG']._serialized_end=1591
|
||||
_globals['_LOCALCONFIG']._serialized_end=642
|
||||
_globals['_LOCALMODULECONFIG']._serialized_start=645
|
||||
_globals['_LOCALMODULECONFIG']._serialized_end=1653
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
||||
12
meshtastic/protobuf/localonly_pb2.pyi
generated
12
meshtastic/protobuf/localonly_pb2.pyi
generated
@@ -29,6 +29,7 @@ class LocalConfig(google.protobuf.message.Message):
|
||||
LORA_FIELD_NUMBER: builtins.int
|
||||
BLUETOOTH_FIELD_NUMBER: builtins.int
|
||||
VERSION_FIELD_NUMBER: builtins.int
|
||||
SECURITY_FIELD_NUMBER: builtins.int
|
||||
version: builtins.int
|
||||
"""
|
||||
A version integer used to invalidate old save files when we make
|
||||
@@ -77,6 +78,12 @@ class LocalConfig(google.protobuf.message.Message):
|
||||
The part of the config that is specific to the Bluetooth settings
|
||||
"""
|
||||
|
||||
@property
|
||||
def security(self) -> meshtastic.protobuf.config_pb2.Config.SecurityConfig:
|
||||
"""
|
||||
The part of the config that is specific to Security settings
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
@@ -88,9 +95,10 @@ class LocalConfig(google.protobuf.message.Message):
|
||||
lora: meshtastic.protobuf.config_pb2.Config.LoRaConfig | None = ...,
|
||||
bluetooth: meshtastic.protobuf.config_pb2.Config.BluetoothConfig | None = ...,
|
||||
version: builtins.int = ...,
|
||||
security: meshtastic.protobuf.config_pb2.Config.SecurityConfig | None = ...,
|
||||
) -> None: ...
|
||||
def HasField(self, field_name: typing.Literal["bluetooth", b"bluetooth", "device", b"device", "display", b"display", "lora", b"lora", "network", b"network", "position", b"position", "power", b"power"]) -> builtins.bool: ...
|
||||
def ClearField(self, field_name: typing.Literal["bluetooth", b"bluetooth", "device", b"device", "display", b"display", "lora", b"lora", "network", b"network", "position", b"position", "power", b"power", "version", b"version"]) -> None: ...
|
||||
def HasField(self, field_name: typing.Literal["bluetooth", b"bluetooth", "device", b"device", "display", b"display", "lora", b"lora", "network", b"network", "position", b"position", "power", b"power", "security", b"security"]) -> builtins.bool: ...
|
||||
def ClearField(self, field_name: typing.Literal["bluetooth", b"bluetooth", "device", b"device", "display", b"display", "lora", b"lora", "network", b"network", "position", b"position", "power", b"power", "security", b"security", "version", b"version"]) -> None: ...
|
||||
|
||||
global___LocalConfig = LocalConfig
|
||||
|
||||
|
||||
139
meshtastic/protobuf/mesh_pb2.py
generated
139
meshtastic/protobuf/mesh_pb2.py
generated
File diff suppressed because one or more lines are too long
714
meshtastic/protobuf/mesh_pb2.pyi
generated
714
meshtastic/protobuf/mesh_pb2.pyi
generated
File diff suppressed because it is too large
Load Diff
72
meshtastic/protobuf/module_config_pb2.py
generated
72
meshtastic/protobuf/module_config_pb2.py
generated
File diff suppressed because one or more lines are too long
113
meshtastic/protobuf/module_config_pb2.pyi
generated
113
meshtastic/protobuf/module_config_pb2.pyi
generated
@@ -225,6 +225,7 @@ class ModuleConfig(google.protobuf.message.Message):
|
||||
|
||||
ENABLED_FIELD_NUMBER: builtins.int
|
||||
UPDATE_INTERVAL_FIELD_NUMBER: builtins.int
|
||||
TRANSMIT_OVER_LORA_FIELD_NUMBER: builtins.int
|
||||
enabled: builtins.bool
|
||||
"""
|
||||
Whether the Module is enabled
|
||||
@@ -232,15 +233,21 @@ class ModuleConfig(google.protobuf.message.Message):
|
||||
update_interval: builtins.int
|
||||
"""
|
||||
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__(
|
||||
self,
|
||||
*,
|
||||
enabled: builtins.bool = ...,
|
||||
update_interval: builtins.int = ...,
|
||||
transmit_over_lora: builtins.bool = ...,
|
||||
) -> 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
|
||||
class DetectionSensorConfig(google.protobuf.message.Message):
|
||||
@@ -250,13 +257,54 @@ class ModuleConfig(google.protobuf.message.Message):
|
||||
|
||||
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||
|
||||
class _TriggerType:
|
||||
ValueType = typing.NewType("ValueType", builtins.int)
|
||||
V: typing_extensions.TypeAlias = ValueType
|
||||
|
||||
class _TriggerTypeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[ModuleConfig.DetectionSensorConfig._TriggerType.ValueType], builtins.type):
|
||||
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
|
||||
LOGIC_LOW: ModuleConfig.DetectionSensorConfig._TriggerType.ValueType # 0
|
||||
"""Event is triggered if pin is low"""
|
||||
LOGIC_HIGH: ModuleConfig.DetectionSensorConfig._TriggerType.ValueType # 1
|
||||
"""Event is triggered if pin is high"""
|
||||
FALLING_EDGE: ModuleConfig.DetectionSensorConfig._TriggerType.ValueType # 2
|
||||
"""Event is triggered when pin goes high to low"""
|
||||
RISING_EDGE: ModuleConfig.DetectionSensorConfig._TriggerType.ValueType # 3
|
||||
"""Event is triggered when pin goes low to high"""
|
||||
EITHER_EDGE_ACTIVE_LOW: ModuleConfig.DetectionSensorConfig._TriggerType.ValueType # 4
|
||||
"""Event is triggered on every pin state change, low is considered to be
|
||||
"active"
|
||||
"""
|
||||
EITHER_EDGE_ACTIVE_HIGH: ModuleConfig.DetectionSensorConfig._TriggerType.ValueType # 5
|
||||
"""Event is triggered on every pin state change, high is considered to be
|
||||
"active"
|
||||
"""
|
||||
|
||||
class TriggerType(_TriggerType, metaclass=_TriggerTypeEnumTypeWrapper): ...
|
||||
LOGIC_LOW: ModuleConfig.DetectionSensorConfig.TriggerType.ValueType # 0
|
||||
"""Event is triggered if pin is low"""
|
||||
LOGIC_HIGH: ModuleConfig.DetectionSensorConfig.TriggerType.ValueType # 1
|
||||
"""Event is triggered if pin is high"""
|
||||
FALLING_EDGE: ModuleConfig.DetectionSensorConfig.TriggerType.ValueType # 2
|
||||
"""Event is triggered when pin goes high to low"""
|
||||
RISING_EDGE: ModuleConfig.DetectionSensorConfig.TriggerType.ValueType # 3
|
||||
"""Event is triggered when pin goes low to high"""
|
||||
EITHER_EDGE_ACTIVE_LOW: ModuleConfig.DetectionSensorConfig.TriggerType.ValueType # 4
|
||||
"""Event is triggered on every pin state change, low is considered to be
|
||||
"active"
|
||||
"""
|
||||
EITHER_EDGE_ACTIVE_HIGH: ModuleConfig.DetectionSensorConfig.TriggerType.ValueType # 5
|
||||
"""Event is triggered on every pin state change, high is considered to be
|
||||
"active"
|
||||
"""
|
||||
|
||||
ENABLED_FIELD_NUMBER: builtins.int
|
||||
MINIMUM_BROADCAST_SECS_FIELD_NUMBER: builtins.int
|
||||
STATE_BROADCAST_SECS_FIELD_NUMBER: builtins.int
|
||||
SEND_BELL_FIELD_NUMBER: builtins.int
|
||||
NAME_FIELD_NUMBER: builtins.int
|
||||
MONITOR_PIN_FIELD_NUMBER: builtins.int
|
||||
DETECTION_TRIGGERED_HIGH_FIELD_NUMBER: builtins.int
|
||||
DETECTION_TRIGGER_TYPE_FIELD_NUMBER: builtins.int
|
||||
USE_PULLUP_FIELD_NUMBER: builtins.int
|
||||
enabled: builtins.bool
|
||||
"""
|
||||
@@ -264,13 +312,15 @@ class ModuleConfig(google.protobuf.message.Message):
|
||||
"""
|
||||
minimum_broadcast_secs: builtins.int
|
||||
"""
|
||||
Interval in seconds of how often we can send a message to the mesh when a state change is detected
|
||||
Interval in seconds of how often we can send a message to the mesh when a
|
||||
trigger event is detected
|
||||
"""
|
||||
state_broadcast_secs: builtins.int
|
||||
"""
|
||||
Interval in seconds of how often we should send a message to the mesh with the current state regardless of changes
|
||||
When set to 0, only state changes will be broadcasted
|
||||
Works as a sort of status heartbeat for peace of mind
|
||||
Interval in seconds of how often we should send a message to the mesh
|
||||
with the current state regardless of trigger events When set to 0, only
|
||||
trigger events will be broadcasted Works as a sort of status heartbeat
|
||||
for peace of mind
|
||||
"""
|
||||
send_bell: builtins.bool
|
||||
"""
|
||||
@@ -287,10 +337,9 @@ class ModuleConfig(google.protobuf.message.Message):
|
||||
"""
|
||||
GPIO pin to monitor for state changes
|
||||
"""
|
||||
detection_triggered_high: builtins.bool
|
||||
detection_trigger_type: global___ModuleConfig.DetectionSensorConfig.TriggerType.ValueType
|
||||
"""
|
||||
Whether or not the GPIO pin state detection is triggered on HIGH (1)
|
||||
Otherwise LOW (0)
|
||||
The type of trigger event to be used
|
||||
"""
|
||||
use_pullup: builtins.bool
|
||||
"""
|
||||
@@ -306,10 +355,10 @@ class ModuleConfig(google.protobuf.message.Message):
|
||||
send_bell: builtins.bool = ...,
|
||||
name: builtins.str = ...,
|
||||
monitor_pin: builtins.int = ...,
|
||||
detection_triggered_high: builtins.bool = ...,
|
||||
detection_trigger_type: global___ModuleConfig.DetectionSensorConfig.TriggerType.ValueType = ...,
|
||||
use_pullup: builtins.bool = ...,
|
||||
) -> None: ...
|
||||
def ClearField(self, field_name: typing.Literal["detection_triggered_high", b"detection_triggered_high", "enabled", b"enabled", "minimum_broadcast_secs", b"minimum_broadcast_secs", "monitor_pin", b"monitor_pin", "name", b"name", "send_bell", b"send_bell", "state_broadcast_secs", b"state_broadcast_secs", "use_pullup", b"use_pullup"]) -> None: ...
|
||||
def ClearField(self, field_name: typing.Literal["detection_trigger_type", b"detection_trigger_type", "enabled", b"enabled", "minimum_broadcast_secs", b"minimum_broadcast_secs", "monitor_pin", b"monitor_pin", "name", b"name", "send_bell", b"send_bell", "state_broadcast_secs", b"state_broadcast_secs", "use_pullup", b"use_pullup"]) -> None: ...
|
||||
|
||||
@typing.final
|
||||
class AudioConfig(google.protobuf.message.Message):
|
||||
@@ -505,6 +554,10 @@ class ModuleConfig(google.protobuf.message.Message):
|
||||
"""NMEA messages specifically tailored for CalTopo"""
|
||||
WS85: ModuleConfig.SerialConfig._Serial_Mode.ValueType # 6
|
||||
"""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
|
||||
"""
|
||||
|
||||
class Serial_Mode(_Serial_Mode, metaclass=_Serial_ModeEnumTypeWrapper):
|
||||
"""
|
||||
@@ -520,6 +573,10 @@ class ModuleConfig(google.protobuf.message.Message):
|
||||
"""NMEA messages specifically tailored for CalTopo"""
|
||||
WS85: ModuleConfig.SerialConfig.Serial_Mode.ValueType # 6
|
||||
"""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
|
||||
"""
|
||||
|
||||
ENABLED_FIELD_NUMBER: builtins.int
|
||||
ECHO_FIELD_NUMBER: builtins.int
|
||||
@@ -793,6 +850,9 @@ class ModuleConfig(google.protobuf.message.Message):
|
||||
POWER_MEASUREMENT_ENABLED_FIELD_NUMBER: builtins.int
|
||||
POWER_UPDATE_INTERVAL_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
|
||||
"""
|
||||
Interval in seconds of how often we should try to send our
|
||||
@@ -828,18 +888,30 @@ class ModuleConfig(google.protobuf.message.Message):
|
||||
"""
|
||||
power_measurement_enabled: builtins.bool
|
||||
"""
|
||||
Interval in seconds of how often we should try to send our
|
||||
air quality metrics to the mesh
|
||||
Enable/disable Power metrics
|
||||
"""
|
||||
power_update_interval: builtins.int
|
||||
"""
|
||||
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
|
||||
"""
|
||||
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
|
||||
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__(
|
||||
self,
|
||||
@@ -854,13 +926,16 @@ class ModuleConfig(google.protobuf.message.Message):
|
||||
power_measurement_enabled: builtins.bool = ...,
|
||||
power_update_interval: builtins.int = ...,
|
||||
power_screen_enabled: builtins.bool = ...,
|
||||
health_measurement_enabled: builtins.bool = ...,
|
||||
health_update_interval: builtins.int = ...,
|
||||
health_screen_enabled: builtins.bool = ...,
|
||||
) -> 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
|
||||
class CannedMessageConfig(google.protobuf.message.Message):
|
||||
"""
|
||||
TODO: REPLACE
|
||||
Canned Messages Module Config
|
||||
"""
|
||||
|
||||
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||
@@ -992,7 +1067,7 @@ class ModuleConfig(google.protobuf.message.Message):
|
||||
allow_input_source: builtins.str
|
||||
"""
|
||||
Input event origin accepted by the canned message module.
|
||||
Can be e.g. "rotEnc1", "upDownEnc1" or keyword "_any"
|
||||
Can be e.g. "rotEnc1", "upDownEnc1", "scanAndSelect", "cardkb", "serialkb", or keyword "_any"
|
||||
"""
|
||||
send_bell: builtins.bool
|
||||
"""
|
||||
|
||||
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*\xcb\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\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\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()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
@@ -22,5 +22,5 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
DESCRIPTOR._options = None
|
||||
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_end=606
|
||||
_globals['_PORTNUM']._serialized_end=647
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
||||
22
meshtastic/protobuf/portnums_pb2.pyi
generated
22
meshtastic/protobuf/portnums_pb2.pyi
generated
@@ -93,6 +93,10 @@ class _PortNumEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTy
|
||||
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
|
||||
"""
|
||||
ALERT_APP: _PortNum.ValueType # 11
|
||||
"""
|
||||
Same as Text Message but used for critical alerts.
|
||||
"""
|
||||
REPLY_APP: _PortNum.ValueType # 32
|
||||
"""
|
||||
Provides a 'ping' service that replies to any packet it receives.
|
||||
@@ -154,7 +158,7 @@ class _PortNumEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTy
|
||||
TRACEROUTE_APP: _PortNum.ValueType # 70
|
||||
"""
|
||||
Provides a traceroute functionality to show the route a packet towards
|
||||
a certain destination would take on the mesh.
|
||||
a certain destination would take on the mesh. Contains a RouteDiscovery message as payload.
|
||||
ENCODING: Protobuf
|
||||
"""
|
||||
NEIGHBORINFO_APP: _PortNum.ValueType # 71
|
||||
@@ -175,6 +179,11 @@ class _PortNumEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTy
|
||||
"""
|
||||
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
|
||||
"""
|
||||
PRIVATE_APP: _PortNum.ValueType # 256
|
||||
"""
|
||||
Private applications should use portnums >= 256.
|
||||
@@ -278,6 +287,10 @@ DETECTION_SENSOR_APP: PortNum.ValueType # 10
|
||||
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
|
||||
"""
|
||||
ALERT_APP: PortNum.ValueType # 11
|
||||
"""
|
||||
Same as Text Message but used for critical alerts.
|
||||
"""
|
||||
REPLY_APP: PortNum.ValueType # 32
|
||||
"""
|
||||
Provides a 'ping' service that replies to any packet it receives.
|
||||
@@ -339,7 +352,7 @@ ENCODING: Protobuf (?)
|
||||
TRACEROUTE_APP: PortNum.ValueType # 70
|
||||
"""
|
||||
Provides a traceroute functionality to show the route a packet towards
|
||||
a certain destination would take on the mesh.
|
||||
a certain destination would take on the mesh. Contains a RouteDiscovery message as payload.
|
||||
ENCODING: Protobuf
|
||||
"""
|
||||
NEIGHBORINFO_APP: PortNum.ValueType # 71
|
||||
@@ -360,6 +373,11 @@ POWERSTRESS_APP: PortNum.ValueType # 74
|
||||
"""
|
||||
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
|
||||
"""
|
||||
PRIVATE_APP: PortNum.ValueType # 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
463
meshtastic/protobuf/telemetry_pb2.pyi
generated
463
meshtastic/protobuf/telemetry_pb2.pyi
generated
@@ -127,6 +127,54 @@ class _TelemetrySensorTypeEnumTypeWrapper(google.protobuf.internal.enum_type_wra
|
||||
"""
|
||||
NAU7802 Scale Chip or compatible
|
||||
"""
|
||||
BMP3XX: _TelemetrySensorType.ValueType # 26
|
||||
"""
|
||||
BMP3XX High accuracy temperature and pressure
|
||||
"""
|
||||
ICM20948: _TelemetrySensorType.ValueType # 27
|
||||
"""
|
||||
ICM-20948 9-Axis digital motion processor
|
||||
"""
|
||||
MAX17048: _TelemetrySensorType.ValueType # 28
|
||||
"""
|
||||
MAX17048 1S lipo battery sensor (voltage, state of charge, time to go)
|
||||
"""
|
||||
CUSTOM_SENSOR: _TelemetrySensorType.ValueType # 29
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
class TelemetrySensorType(_TelemetrySensorType, metaclass=_TelemetrySensorTypeEnumTypeWrapper):
|
||||
"""
|
||||
@@ -237,6 +285,54 @@ NAU7802: TelemetrySensorType.ValueType # 25
|
||||
"""
|
||||
NAU7802 Scale Chip or compatible
|
||||
"""
|
||||
BMP3XX: TelemetrySensorType.ValueType # 26
|
||||
"""
|
||||
BMP3XX High accuracy temperature and pressure
|
||||
"""
|
||||
ICM20948: TelemetrySensorType.ValueType # 27
|
||||
"""
|
||||
ICM-20948 9-Axis digital motion processor
|
||||
"""
|
||||
MAX17048: TelemetrySensorType.ValueType # 28
|
||||
"""
|
||||
MAX17048 1S lipo battery sensor (voltage, state of charge, time to go)
|
||||
"""
|
||||
CUSTOM_SENSOR: TelemetrySensorType.ValueType # 29
|
||||
"""
|
||||
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
|
||||
"""
|
||||
global___TelemetrySensorType = TelemetrySensorType
|
||||
|
||||
@typing.final
|
||||
@@ -275,13 +371,24 @@ class DeviceMetrics(google.protobuf.message.Message):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
battery_level: builtins.int = ...,
|
||||
voltage: builtins.float = ...,
|
||||
channel_utilization: builtins.float = ...,
|
||||
air_util_tx: builtins.float = ...,
|
||||
uptime_seconds: builtins.int = ...,
|
||||
battery_level: builtins.int | None = ...,
|
||||
voltage: builtins.float | None = ...,
|
||||
channel_utilization: builtins.float | None = ...,
|
||||
air_util_tx: builtins.float | None = ...,
|
||||
uptime_seconds: builtins.int | None = ...,
|
||||
) -> None: ...
|
||||
def ClearField(self, field_name: typing.Literal["air_util_tx", b"air_util_tx", "battery_level", b"battery_level", "channel_utilization", b"channel_utilization", "uptime_seconds", b"uptime_seconds", "voltage", b"voltage"]) -> None: ...
|
||||
def HasField(self, field_name: typing.Literal["_air_util_tx", b"_air_util_tx", "_battery_level", b"_battery_level", "_channel_utilization", b"_channel_utilization", "_uptime_seconds", b"_uptime_seconds", "_voltage", b"_voltage", "air_util_tx", b"air_util_tx", "battery_level", b"battery_level", "channel_utilization", b"channel_utilization", "uptime_seconds", b"uptime_seconds", "voltage", b"voltage"]) -> builtins.bool: ...
|
||||
def ClearField(self, field_name: typing.Literal["_air_util_tx", b"_air_util_tx", "_battery_level", b"_battery_level", "_channel_utilization", b"_channel_utilization", "_uptime_seconds", b"_uptime_seconds", "_voltage", b"_voltage", "air_util_tx", b"air_util_tx", "battery_level", b"battery_level", "channel_utilization", b"channel_utilization", "uptime_seconds", b"uptime_seconds", "voltage", b"voltage"]) -> None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_air_util_tx", b"_air_util_tx"]) -> typing.Literal["air_util_tx"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_battery_level", b"_battery_level"]) -> typing.Literal["battery_level"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_channel_utilization", b"_channel_utilization"]) -> typing.Literal["channel_utilization"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_uptime_seconds", b"_uptime_seconds"]) -> typing.Literal["uptime_seconds"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_voltage", b"_voltage"]) -> typing.Literal["voltage"] | None: ...
|
||||
|
||||
global___DeviceMetrics = DeviceMetrics
|
||||
|
||||
@@ -310,6 +417,11 @@ class EnvironmentMetrics(google.protobuf.message.Message):
|
||||
WEIGHT_FIELD_NUMBER: builtins.int
|
||||
WIND_GUST_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 measured
|
||||
@@ -380,28 +492,98 @@ class EnvironmentMetrics(google.protobuf.message.Message):
|
||||
"""
|
||||
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__(
|
||||
self,
|
||||
*,
|
||||
temperature: builtins.float = ...,
|
||||
relative_humidity: builtins.float = ...,
|
||||
barometric_pressure: builtins.float = ...,
|
||||
gas_resistance: builtins.float = ...,
|
||||
voltage: builtins.float = ...,
|
||||
current: builtins.float = ...,
|
||||
iaq: builtins.int = ...,
|
||||
distance: builtins.float = ...,
|
||||
lux: builtins.float = ...,
|
||||
white_lux: builtins.float = ...,
|
||||
ir_lux: builtins.float = ...,
|
||||
uv_lux: builtins.float = ...,
|
||||
wind_direction: builtins.int = ...,
|
||||
wind_speed: builtins.float = ...,
|
||||
weight: builtins.float = ...,
|
||||
wind_gust: builtins.float = ...,
|
||||
wind_lull: builtins.float = ...,
|
||||
temperature: builtins.float | None = ...,
|
||||
relative_humidity: builtins.float | None = ...,
|
||||
barometric_pressure: builtins.float | None = ...,
|
||||
gas_resistance: builtins.float | None = ...,
|
||||
voltage: builtins.float | None = ...,
|
||||
current: builtins.float | None = ...,
|
||||
iaq: builtins.int | None = ...,
|
||||
distance: builtins.float | None = ...,
|
||||
lux: builtins.float | None = ...,
|
||||
white_lux: builtins.float | None = ...,
|
||||
ir_lux: builtins.float | None = ...,
|
||||
uv_lux: builtins.float | None = ...,
|
||||
wind_direction: builtins.int | None = ...,
|
||||
wind_speed: builtins.float | None = ...,
|
||||
weight: builtins.float | None = ...,
|
||||
wind_gust: 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: ...
|
||||
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"]) -> 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", "_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", "_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
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_barometric_pressure", b"_barometric_pressure"]) -> typing.Literal["barometric_pressure"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_current", b"_current"]) -> typing.Literal["current"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_distance", b"_distance"]) -> typing.Literal["distance"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_gas_resistance", b"_gas_resistance"]) -> typing.Literal["gas_resistance"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_iaq", b"_iaq"]) -> typing.Literal["iaq"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_ir_lux", b"_ir_lux"]) -> typing.Literal["ir_lux"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_lux", b"_lux"]) -> typing.Literal["lux"] | None: ...
|
||||
@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: ...
|
||||
@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: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_uv_lux", b"_uv_lux"]) -> typing.Literal["uv_lux"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_voltage", b"_voltage"]) -> typing.Literal["voltage"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_weight", b"_weight"]) -> typing.Literal["weight"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_white_lux", b"_white_lux"]) -> typing.Literal["white_lux"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_wind_direction", b"_wind_direction"]) -> typing.Literal["wind_direction"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_wind_gust", b"_wind_gust"]) -> typing.Literal["wind_gust"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_wind_lull", b"_wind_lull"]) -> typing.Literal["wind_lull"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_wind_speed", b"_wind_speed"]) -> typing.Literal["wind_speed"] | None: ...
|
||||
|
||||
global___EnvironmentMetrics = EnvironmentMetrics
|
||||
|
||||
@@ -446,14 +628,27 @@ class PowerMetrics(google.protobuf.message.Message):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
ch1_voltage: builtins.float = ...,
|
||||
ch1_current: builtins.float = ...,
|
||||
ch2_voltage: builtins.float = ...,
|
||||
ch2_current: builtins.float = ...,
|
||||
ch3_voltage: builtins.float = ...,
|
||||
ch3_current: builtins.float = ...,
|
||||
ch1_voltage: builtins.float | None = ...,
|
||||
ch1_current: builtins.float | None = ...,
|
||||
ch2_voltage: builtins.float | None = ...,
|
||||
ch2_current: builtins.float | None = ...,
|
||||
ch3_voltage: builtins.float | None = ...,
|
||||
ch3_current: builtins.float | None = ...,
|
||||
) -> 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"]) -> 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 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: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_ch1_current", b"_ch1_current"]) -> typing.Literal["ch1_current"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_ch1_voltage", b"_ch1_voltage"]) -> typing.Literal["ch1_voltage"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_ch2_current", b"_ch2_current"]) -> typing.Literal["ch2_current"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_ch2_voltage", b"_ch2_voltage"]) -> typing.Literal["ch2_voltage"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_ch3_current", b"_ch3_current"]) -> typing.Literal["ch3_current"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_ch3_voltage", b"_ch3_voltage"]) -> typing.Literal["ch3_voltage"] | None: ...
|
||||
|
||||
global___PowerMetrics = PowerMetrics
|
||||
|
||||
@@ -477,6 +672,7 @@ class AirQualityMetrics(google.protobuf.message.Message):
|
||||
PARTICLES_25UM_FIELD_NUMBER: builtins.int
|
||||
PARTICLES_50UM_FIELD_NUMBER: builtins.int
|
||||
PARTICLES_100UM_FIELD_NUMBER: builtins.int
|
||||
CO2_FIELD_NUMBER: builtins.int
|
||||
pm10_standard: builtins.int
|
||||
"""
|
||||
Concentration Units Standard PM1.0
|
||||
@@ -525,26 +721,183 @@ class AirQualityMetrics(google.protobuf.message.Message):
|
||||
"""
|
||||
10.0um Particle Count
|
||||
"""
|
||||
co2: builtins.int
|
||||
"""
|
||||
CO2 concentration in ppm
|
||||
"""
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
pm10_standard: builtins.int = ...,
|
||||
pm25_standard: builtins.int = ...,
|
||||
pm100_standard: builtins.int = ...,
|
||||
pm10_environmental: builtins.int = ...,
|
||||
pm25_environmental: builtins.int = ...,
|
||||
pm100_environmental: builtins.int = ...,
|
||||
particles_03um: builtins.int = ...,
|
||||
particles_05um: builtins.int = ...,
|
||||
particles_10um: builtins.int = ...,
|
||||
particles_25um: builtins.int = ...,
|
||||
particles_50um: builtins.int = ...,
|
||||
particles_100um: builtins.int = ...,
|
||||
pm10_standard: builtins.int | None = ...,
|
||||
pm25_standard: builtins.int | None = ...,
|
||||
pm100_standard: builtins.int | None = ...,
|
||||
pm10_environmental: builtins.int | None = ...,
|
||||
pm25_environmental: builtins.int | None = ...,
|
||||
pm100_environmental: builtins.int | None = ...,
|
||||
particles_03um: builtins.int | None = ...,
|
||||
particles_05um: builtins.int | None = ...,
|
||||
particles_10um: builtins.int | None = ...,
|
||||
particles_25um: builtins.int | None = ...,
|
||||
particles_50um: builtins.int | None = ...,
|
||||
particles_100um: builtins.int | None = ...,
|
||||
co2: builtins.int | None = ...,
|
||||
) -> None: ...
|
||||
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"]) -> None: ...
|
||||
def HasField(self, field_name: typing.Literal["_co2", b"_co2", "_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", "co2", b"co2", "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 ClearField(self, field_name: typing.Literal["_co2", b"_co2", "_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", "co2", b"co2", "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: ...
|
||||
@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["_particles_03um", b"_particles_03um"]) -> typing.Literal["particles_03um"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_particles_05um", b"_particles_05um"]) -> typing.Literal["particles_05um"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_particles_100um", b"_particles_100um"]) -> typing.Literal["particles_100um"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_particles_10um", b"_particles_10um"]) -> typing.Literal["particles_10um"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_particles_25um", b"_particles_25um"]) -> typing.Literal["particles_25um"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_particles_50um", b"_particles_50um"]) -> typing.Literal["particles_50um"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_pm100_environmental", b"_pm100_environmental"]) -> typing.Literal["pm100_environmental"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_pm100_standard", b"_pm100_standard"]) -> typing.Literal["pm100_standard"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_pm10_environmental", b"_pm10_environmental"]) -> typing.Literal["pm10_environmental"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_pm10_standard", b"_pm10_standard"]) -> typing.Literal["pm10_standard"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_pm25_environmental", b"_pm25_environmental"]) -> typing.Literal["pm25_environmental"] | None: ...
|
||||
@typing.overload
|
||||
def WhichOneof(self, oneof_group: typing.Literal["_pm25_standard", b"_pm25_standard"]) -> typing.Literal["pm25_standard"] | None: ...
|
||||
|
||||
global___AirQualityMetrics = AirQualityMetrics
|
||||
|
||||
@typing.final
|
||||
class LocalStats(google.protobuf.message.Message):
|
||||
"""
|
||||
Local device mesh statistics
|
||||
"""
|
||||
|
||||
DESCRIPTOR: google.protobuf.descriptor.Descriptor
|
||||
|
||||
UPTIME_SECONDS_FIELD_NUMBER: builtins.int
|
||||
CHANNEL_UTILIZATION_FIELD_NUMBER: builtins.int
|
||||
AIR_UTIL_TX_FIELD_NUMBER: builtins.int
|
||||
NUM_PACKETS_TX_FIELD_NUMBER: builtins.int
|
||||
NUM_PACKETS_RX_FIELD_NUMBER: builtins.int
|
||||
NUM_PACKETS_RX_BAD_FIELD_NUMBER: builtins.int
|
||||
NUM_ONLINE_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
|
||||
uptime_seconds: builtins.int
|
||||
"""
|
||||
How long the device has been running since the last reboot (in seconds)
|
||||
"""
|
||||
channel_utilization: builtins.float
|
||||
"""
|
||||
Utilization for the current channel, including well formed TX, RX and malformed RX (aka noise).
|
||||
"""
|
||||
air_util_tx: builtins.float
|
||||
"""
|
||||
Percent of airtime for transmission used within the last hour.
|
||||
"""
|
||||
num_packets_tx: builtins.int
|
||||
"""
|
||||
Number of packets sent
|
||||
"""
|
||||
num_packets_rx: builtins.int
|
||||
"""
|
||||
Number of packets received (both good and bad)
|
||||
"""
|
||||
num_packets_rx_bad: builtins.int
|
||||
"""
|
||||
Number of packets received that are malformed or violate the protocol
|
||||
"""
|
||||
num_online_nodes: builtins.int
|
||||
"""
|
||||
Number of nodes online (in the past 2 hours)
|
||||
"""
|
||||
num_total_nodes: builtins.int
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
uptime_seconds: builtins.int = ...,
|
||||
channel_utilization: builtins.float = ...,
|
||||
air_util_tx: builtins.float = ...,
|
||||
num_packets_tx: builtins.int = ...,
|
||||
num_packets_rx: builtins.int = ...,
|
||||
num_packets_rx_bad: builtins.int = ...,
|
||||
num_online_nodes: builtins.int = ...,
|
||||
num_total_nodes: builtins.int = ...,
|
||||
num_rx_dupe: builtins.int = ...,
|
||||
num_tx_relay: builtins.int = ...,
|
||||
num_tx_relay_canceled: builtins.int = ...,
|
||||
) -> 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_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
|
||||
|
||||
@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 Telemetry(google.protobuf.message.Message):
|
||||
"""
|
||||
@@ -558,6 +911,8 @@ class Telemetry(google.protobuf.message.Message):
|
||||
ENVIRONMENT_METRICS_FIELD_NUMBER: builtins.int
|
||||
AIR_QUALITY_METRICS_FIELD_NUMBER: builtins.int
|
||||
POWER_METRICS_FIELD_NUMBER: builtins.int
|
||||
LOCAL_STATS_FIELD_NUMBER: builtins.int
|
||||
HEALTH_METRICS_FIELD_NUMBER: builtins.int
|
||||
time: builtins.int
|
||||
"""
|
||||
Seconds since 1970 - or 0 for unknown/unset
|
||||
@@ -586,6 +941,18 @@ class Telemetry(google.protobuf.message.Message):
|
||||
Power Metrics
|
||||
"""
|
||||
|
||||
@property
|
||||
def local_stats(self) -> global___LocalStats:
|
||||
"""
|
||||
Local device mesh statistics
|
||||
"""
|
||||
|
||||
@property
|
||||
def health_metrics(self) -> global___HealthMetrics:
|
||||
"""
|
||||
Health telemetry metrics
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
@@ -594,10 +961,12 @@ class Telemetry(google.protobuf.message.Message):
|
||||
environment_metrics: global___EnvironmentMetrics | None = ...,
|
||||
air_quality_metrics: global___AirQualityMetrics | None = ...,
|
||||
power_metrics: global___PowerMetrics | None = ...,
|
||||
local_stats: global___LocalStats | None = ...,
|
||||
health_metrics: global___HealthMetrics | 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", "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", "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"] | 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", "health_metrics", b"health_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", "health_metrics", b"health_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", "health_metrics"] | None: ...
|
||||
|
||||
global___Telemetry = Telemetry
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ from meshtastic.protobuf import portnums_pb2, remote_hardware_pb2
|
||||
from meshtastic.util import our_exit
|
||||
|
||||
|
||||
def onGPIOreceive(packet, interface):
|
||||
def onGPIOreceive(packet, interface) -> None:
|
||||
"""Callback for received GPIO responses"""
|
||||
logging.debug(f"packet:{packet} interface:{interface}")
|
||||
gpioValue = 0
|
||||
@@ -37,7 +37,7 @@ class RemoteHardwareClient:
|
||||
code for how you can connect to your own custom meshtastic services
|
||||
"""
|
||||
|
||||
def __init__(self, iface):
|
||||
def __init__(self, iface) -> None:
|
||||
"""
|
||||
Constructor
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
""" Serial interface class
|
||||
"""
|
||||
# pylint: disable=R0917
|
||||
import logging
|
||||
import platform
|
||||
import time
|
||||
|
||||
from typing import Optional
|
||||
from typing import List, Optional
|
||||
|
||||
import serial # type: ignore[import-untyped]
|
||||
|
||||
@@ -18,7 +19,7 @@ if platform.system() != "Windows":
|
||||
class SerialInterface(StreamInterface):
|
||||
"""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
|
||||
find one Meshtastic device by probing
|
||||
|
||||
@@ -31,13 +32,13 @@ class SerialInterface(StreamInterface):
|
||||
self.devPath: Optional[str] = devPath
|
||||
|
||||
if self.devPath is None:
|
||||
ports = meshtastic.util.findPorts(True)
|
||||
ports: List[str] = meshtastic.util.findPorts(True)
|
||||
logging.debug(f"ports:{ports}")
|
||||
if len(ports) == 0:
|
||||
print("No Serial Meshtastic device detected, attempting TCP connection on localhost.")
|
||||
return
|
||||
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}"
|
||||
meshtastic.util.our_exit(message)
|
||||
else:
|
||||
@@ -58,14 +59,25 @@ class SerialInterface(StreamInterface):
|
||||
self.stream = serial.Serial(
|
||||
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)
|
||||
|
||||
StreamInterface.__init__(
|
||||
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"""
|
||||
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
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
"""Stream Interface base class
|
||||
"""
|
||||
import io
|
||||
import logging
|
||||
import threading
|
||||
import time
|
||||
import traceback
|
||||
|
||||
from typing import Optional, cast
|
||||
|
||||
import serial # type: ignore[import-untyped]
|
||||
|
||||
from meshtastic.mesh_interface import MeshInterface
|
||||
@@ -19,7 +22,7 @@ MAX_TO_FROM_RADIO_SIZE = 512
|
||||
class StreamInterface(MeshInterface):
|
||||
"""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
|
||||
|
||||
Keyword Arguments:
|
||||
@@ -35,6 +38,7 @@ class StreamInterface(MeshInterface):
|
||||
raise Exception( # pylint: disable=W0719
|
||||
"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._wantExit = False
|
||||
|
||||
@@ -52,7 +56,7 @@ class StreamInterface(MeshInterface):
|
||||
if not noProto:
|
||||
self.waitForConfig()
|
||||
|
||||
def connect(self):
|
||||
def connect(self) -> None:
|
||||
"""Connect to our radio
|
||||
|
||||
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
|
||||
# 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)
|
||||
p = bytearray([START2] * 32)
|
||||
p: bytes = bytearray([START2] * 32)
|
||||
self._writeBytes(p)
|
||||
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
|
||||
self._waitConnected()
|
||||
|
||||
def _disconnected(self):
|
||||
def _disconnected(self) -> None:
|
||||
"""We override the superclass implementation to close our port"""
|
||||
MeshInterface._disconnected(self)
|
||||
|
||||
@@ -86,7 +90,7 @@ class StreamInterface(MeshInterface):
|
||||
# pylint: disable=W0201
|
||||
self.stream = None
|
||||
|
||||
def _writeBytes(self, b):
|
||||
def _writeBytes(self, b: bytes) -> None:
|
||||
"""Write an array of bytes to our stream and flush"""
|
||||
if self.stream: # ignore writes when stream is closed
|
||||
self.stream.write(b)
|
||||
@@ -98,24 +102,24 @@ class StreamInterface(MeshInterface):
|
||||
# we sleep here to give the TBeam a chance to work
|
||||
time.sleep(0.1)
|
||||
|
||||
def _readBytes(self, length):
|
||||
def _readBytes(self, length) -> Optional[bytes]:
|
||||
"""Read an array of bytes from our stream"""
|
||||
if self.stream:
|
||||
return self.stream.read(length)
|
||||
else:
|
||||
return None
|
||||
|
||||
def _sendToRadioImpl(self, toRadio):
|
||||
def _sendToRadioImpl(self, toRadio) -> None:
|
||||
"""Send a ToRadio protobuf to the device"""
|
||||
logging.debug(f"Sending: {stripnl(toRadio)}")
|
||||
b = toRadio.SerializeToString()
|
||||
bufLen = len(b)
|
||||
b: bytes = toRadio.SerializeToString()
|
||||
bufLen: int = len(b)
|
||||
# We convert into a string, because the TCP code doesn't work with byte arrays
|
||||
header = bytes([START1, START2, (bufLen >> 8) & 0xFF, bufLen & 0xFF])
|
||||
logging.debug(f"sending header:{header} b:{b}")
|
||||
header: bytes = bytes([START1, START2, (bufLen >> 8) & 0xFF, bufLen & 0xFF])
|
||||
logging.debug(f"sending header:{header!r} b:{b!r}")
|
||||
self._writeBytes(header + b)
|
||||
|
||||
def close(self):
|
||||
def close(self) -> None:
|
||||
"""Close a connection to the device"""
|
||||
logging.debug("Closing stream")
|
||||
MeshInterface.close(self)
|
||||
@@ -142,7 +146,7 @@ class StreamInterface(MeshInterface):
|
||||
else:
|
||||
self.cur_log_line += utf
|
||||
|
||||
def __reader(self):
|
||||
def __reader(self) -> None:
|
||||
"""The reader thread that reads bytes from our stream"""
|
||||
logging.debug("in __reader()")
|
||||
empty = bytes()
|
||||
@@ -150,13 +154,13 @@ class StreamInterface(MeshInterface):
|
||||
try:
|
||||
while not self._wantExit:
|
||||
# logging.debug("reading character")
|
||||
b = self._readBytes(1)
|
||||
b: Optional[bytes] = self._readBytes(1)
|
||||
# logging.debug("In reader loop")
|
||||
# logging.debug(f"read returned {b}")
|
||||
if len(b) > 0:
|
||||
c = b[0]
|
||||
if b is not None and len(cast(bytes, b)) > 0:
|
||||
c: int = b[0]
|
||||
# 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
|
||||
self._rxBuf = self._rxBuf + b
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
""" Supported Meshtastic Devices - This is a class and collection of Meshtastic devices.
|
||||
It is used for auto detection as to which device might be connected.
|
||||
"""
|
||||
# pylint: disable=R0917
|
||||
|
||||
# Goal is to detect which device and port to use from the supported devices
|
||||
# without installing any libraries that are not currently in the python meshtastic library
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
"""TCPInterface class for interfacing with http endpoint
|
||||
"""
|
||||
# pylint: disable=R0917
|
||||
import contextlib
|
||||
import logging
|
||||
import socket
|
||||
import time
|
||||
from typing import Optional
|
||||
|
||||
from meshtastic.stream_interface import StreamInterface
|
||||
|
||||
DEFAULT_TCP_PORT = 4403
|
||||
|
||||
class TCPInterface(StreamInterface):
|
||||
"""Interface class for meshtastic devices over a TCP link"""
|
||||
@@ -14,9 +18,9 @@ class TCPInterface(StreamInterface):
|
||||
self,
|
||||
hostname: str,
|
||||
debugOut=None,
|
||||
noProto=False,
|
||||
connectNow=True,
|
||||
portNumber=4403,
|
||||
noProto: bool=False,
|
||||
connectNow: bool=True,
|
||||
portNumber: int=DEFAULT_TCP_PORT,
|
||||
noNodes:bool=False,
|
||||
):
|
||||
"""Constructor, opens a connection to a specified IP address/hostname
|
||||
@@ -27,51 +31,84 @@ class TCPInterface(StreamInterface):
|
||||
|
||||
self.stream = None
|
||||
|
||||
self.hostname = hostname
|
||||
self.portNumber = portNumber
|
||||
self.hostname: str = hostname
|
||||
self.portNumber: int = portNumber
|
||||
|
||||
self.socket: Optional[socket.socket] = None
|
||||
|
||||
if connectNow:
|
||||
logging.debug(f"Connecting to {hostname}") # type: ignore[str-bytes-safe]
|
||||
server_address = (hostname, portNumber)
|
||||
sock = socket.create_connection(server_address)
|
||||
self.socket: Optional[socket.socket] = sock
|
||||
self.myConnect()
|
||||
else:
|
||||
self.socket = None
|
||||
|
||||
StreamInterface.__init__(
|
||||
self, debugOut=debugOut, noProto=noProto, connectNow=connectNow, noNodes=noNodes
|
||||
)
|
||||
super().__init__(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.
|
||||
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"""
|
||||
logging.debug(f"Connecting to {self.hostname}") # type: ignore[str-bytes-safe]
|
||||
server_address = (self.hostname, self.portNumber)
|
||||
sock = socket.create_connection(server_address)
|
||||
self.socket = sock
|
||||
self.socket = socket.create_connection(server_address)
|
||||
|
||||
def close(self):
|
||||
def close(self) -> None:
|
||||
"""Close a connection to the device"""
|
||||
logging.debug("Closing TCP stream")
|
||||
StreamInterface.close(self)
|
||||
super().close()
|
||||
# Sometimes the socket read might be blocked in the reader thread.
|
||||
# Therefore we force the shutdown by closing the socket here
|
||||
self._wantExit = True
|
||||
if not self.socket is None:
|
||||
try:
|
||||
if self.socket is not None:
|
||||
with contextlib.suppress(Exception): # Ignore errors in shutdown, because we might have a race with the server
|
||||
self._socket_shutdown()
|
||||
except:
|
||||
pass # Ignore errors in shutdown, because we might have a race with the server
|
||||
self.socket.close()
|
||||
|
||||
def _writeBytes(self, b):
|
||||
"""Write an array of bytes to our stream and flush"""
|
||||
self.socket.send(b)
|
||||
self.socket = None
|
||||
|
||||
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"""
|
||||
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 time
|
||||
import traceback
|
||||
import io
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
from dotmap import DotMap # 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
|
||||
|
||||
"""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"""
|
||||
receivedPackets = None
|
||||
receivedPackets: Optional[List] = None
|
||||
|
||||
testsRunning = False
|
||||
testsRunning: bool = False
|
||||
|
||||
testNumber = 0
|
||||
testNumber: int = 0
|
||||
|
||||
sendingInterface = None
|
||||
|
||||
|
||||
def onReceive(packet, interface):
|
||||
def onReceive(packet, interface) -> None:
|
||||
"""Callback invoked when a packet arrives"""
|
||||
if sendingInterface == interface:
|
||||
pass
|
||||
@@ -42,20 +45,20 @@ def onReceive(packet, interface):
|
||||
receivedPackets.append(p)
|
||||
|
||||
|
||||
def onNode(node):
|
||||
def onNode(node) -> None:
|
||||
"""Callback invoked when the node DB changes"""
|
||||
print(f"Node changed: {node}")
|
||||
|
||||
|
||||
def subscribe():
|
||||
def subscribe() -> None:
|
||||
"""Subscribe to the topics the user probably wants to see, prints output to stdout"""
|
||||
|
||||
pub.subscribe(onNode, "meshtastic.node")
|
||||
|
||||
|
||||
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
|
||||
|
||||
@@ -93,16 +96,16 @@ def testSend(
|
||||
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."""
|
||||
logging.info(f"Running {numTests} tests with wantAck={wantAck}")
|
||||
numFail = 0
|
||||
numSuccess = 0
|
||||
numFail: int = 0
|
||||
numSuccess: int = 0
|
||||
for _ in range(numTests):
|
||||
# pylint: disable=W0603
|
||||
global testNumber
|
||||
testNumber = testNumber + 1
|
||||
isBroadcast = True
|
||||
isBroadcast:bool = True
|
||||
# asBinary=(i % 2 == 0)
|
||||
success = testSend(
|
||||
interfaces[0], interfaces[1], isBroadcast, asBinary=False, wantAck=wantAck
|
||||
@@ -126,10 +129,10 @@ def runTests(numTests=50, wantAck=False, maxFailures=0):
|
||||
return True
|
||||
|
||||
|
||||
def testThread(numTests=50):
|
||||
def testThread(numTests=50) -> bool:
|
||||
"""Test thread"""
|
||||
logging.info("Found devices, starting tests...")
|
||||
result = runTests(numTests, wantAck=True)
|
||||
result: bool = runTests(numTests, wantAck=True)
|
||||
if result:
|
||||
# Run another test
|
||||
# Allow a few dropped packets
|
||||
@@ -137,25 +140,25 @@ def testThread(numTests=50):
|
||||
return result
|
||||
|
||||
|
||||
def onConnection(topic=pub.AUTO_TOPIC):
|
||||
def onConnection(topic=pub.AUTO_TOPIC) -> None:
|
||||
"""Callback invoked when we connect/disconnect from a radio"""
|
||||
print(f"Connection changed: {topic.getName()}")
|
||||
|
||||
|
||||
def openDebugLog(portName):
|
||||
def openDebugLog(portName) -> io.TextIOWrapper:
|
||||
"""Open the debug log file"""
|
||||
debugname = "log" + portName.replace("/", "_")
|
||||
logging.info(f"Writing serial debugging to {debugname}")
|
||||
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.
|
||||
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:
|
||||
meshtastic.util.our_exit(
|
||||
"Warning: Must have at least two devices connected to USB."
|
||||
@@ -175,7 +178,7 @@ def testAll(numTests=5):
|
||||
)
|
||||
|
||||
logging.info("Ports opened, starting test")
|
||||
result = testThread(numTests)
|
||||
result: bool = testThread(numTests)
|
||||
|
||||
for i in interfaces:
|
||||
i.close()
|
||||
@@ -183,7 +186,7 @@ def testAll(numTests=5):
|
||||
return result
|
||||
|
||||
|
||||
def testSimulator():
|
||||
def testSimulator() -> None:
|
||||
"""
|
||||
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
|
||||
@@ -195,7 +198,7 @@ def testSimulator():
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logging.info("Connecting to simulator on localhost!")
|
||||
try:
|
||||
iface = TCPInterface("localhost")
|
||||
iface: meshtastic.tcp_interface.TCPInterface = TCPInterface("localhost")
|
||||
iface.showInfo()
|
||||
iface.localNode.showInfo()
|
||||
iface.localNode.exitSimulator()
|
||||
|
||||
@@ -6,7 +6,11 @@ import sys
|
||||
|
||||
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""Meshtastic unit tests for __main__.py"""
|
||||
# pylint: disable=C0302,W0613
|
||||
# pylint: disable=C0302,W0613,R0917
|
||||
|
||||
import logging
|
||||
import os
|
||||
@@ -408,8 +408,8 @@ def test_main_nodes(capsys):
|
||||
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
|
||||
def mock_showNodes():
|
||||
print("inside mocked showNodes")
|
||||
def mock_showNodes(includeSelf, showFields):
|
||||
print(f"inside mocked showNodes: {includeSelf} {showFields}")
|
||||
|
||||
iface.showNodes.side_effect = mock_showNodes
|
||||
with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
|
||||
@@ -593,10 +593,10 @@ def test_main_sendtext(capsys):
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
|
||||
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(f"{text} {dest} {wantAck} {wantResponse} {channelIndex}")
|
||||
print(f"{text} {dest} {wantAck} {wantResponse} {channelIndex} {portNum}")
|
||||
|
||||
iface.sendText.side_effect = mock_sendText
|
||||
|
||||
@@ -620,10 +620,10 @@ def test_main_sendtext_with_channel(capsys):
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
|
||||
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(f"{text} {dest} {wantAck} {wantResponse} {channelIndex}")
|
||||
print(f"{text} {dest} {wantAck} {wantResponse} {channelIndex} {portNum}")
|
||||
|
||||
iface.sendText.side_effect = mock_sendText
|
||||
|
||||
@@ -726,8 +726,8 @@ def test_main_sendtext_with_dest(mock_findPorts, mock_serial, mocked_open, mock_
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.usefixtures("reset_mt_config")
|
||||
def test_main_removeposition_invalid(capsys):
|
||||
"""Test --remove-position with an invalid dest"""
|
||||
def test_main_removeposition_remote(capsys):
|
||||
"""Test --remove-position with a remote dest"""
|
||||
sys.argv = ["", "--remove-position", "--dest", "!12345678"]
|
||||
mt_config.args = sys.argv
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
@@ -735,14 +735,15 @@ def test_main_removeposition_invalid(capsys):
|
||||
main()
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r"Connected to radio", out, re.MULTILINE)
|
||||
assert re.search(r"remote nodes is not supported", out, re.MULTILINE)
|
||||
assert re.search(r"Removing fixed position and disabling fixed position setting", out, re.MULTILINE)
|
||||
assert re.search(r"Waiting for an acknowledgment from remote node", out, re.MULTILINE)
|
||||
assert err == ""
|
||||
mo.assert_called()
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.usefixtures("reset_mt_config")
|
||||
def test_main_setlat_invalid(capsys):
|
||||
"""Test --setlat with an invalid dest"""
|
||||
def test_main_setlat_remote(capsys):
|
||||
"""Test --setlat with a remote dest"""
|
||||
sys.argv = ["", "--setlat", "37.5", "--dest", "!12345678"]
|
||||
mt_config.args = sys.argv
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
@@ -750,7 +751,8 @@ def test_main_setlat_invalid(capsys):
|
||||
main()
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r"Connected to radio", out, re.MULTILINE)
|
||||
assert re.search(r"remote nodes is not supported", out, re.MULTILINE)
|
||||
assert re.search(r"Setting device position and enabling fixed position setting", out, re.MULTILINE)
|
||||
assert re.search(r"Waiting for an acknowledgment from remote node", out, re.MULTILINE)
|
||||
assert err == ""
|
||||
mo.assert_called()
|
||||
|
||||
@@ -769,7 +771,7 @@ def test_main_removeposition(capsys):
|
||||
mocked_node.removeFixedPosition.side_effect = mock_removeFixedPosition
|
||||
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
iface.localNode = mocked_node
|
||||
iface.getNode.return_value = mocked_node
|
||||
|
||||
with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
|
||||
main()
|
||||
@@ -796,7 +798,7 @@ def test_main_setlat(capsys):
|
||||
mocked_node.setFixedPosition.side_effect = mock_setFixedPosition
|
||||
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
iface.localNode = mocked_node
|
||||
iface.getNode.return_value = mocked_node
|
||||
|
||||
with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
|
||||
main()
|
||||
@@ -825,7 +827,7 @@ def test_main_setlon(capsys):
|
||||
mocked_node.setFixedPosition.side_effect = mock_setFixedPosition
|
||||
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
iface.localNode = mocked_node
|
||||
iface.getNode.return_value = mocked_node
|
||||
|
||||
with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
|
||||
main()
|
||||
@@ -854,7 +856,7 @@ def test_main_setalt(capsys):
|
||||
mocked_node.setFixedPosition.side_effect = mock_setFixedPosition
|
||||
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
iface.localNode = mocked_node
|
||||
iface.getNode.return_value = mocked_node
|
||||
|
||||
with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
|
||||
main()
|
||||
@@ -1606,7 +1608,7 @@ def test_main_onReceive_empty(caplog, capsys):
|
||||
assert re.search(r"in onReceive", caplog.text, re.MULTILINE)
|
||||
out, err = capsys.readouterr()
|
||||
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 == ""
|
||||
|
||||
@@ -2650,3 +2652,64 @@ def test_tunnel_tunnel_arg(
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r"Connected to radio", out, re.MULTILINE)
|
||||
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")
|
||||
|
||||
@@ -11,8 +11,12 @@ from ..protobuf import mesh_pb2, config_pb2
|
||||
from .. import BROADCAST_ADDR, LOCAL_ADDR
|
||||
from ..mesh_interface import MeshInterface, _timeago
|
||||
from ..node import Node
|
||||
from ..slog import LogSet
|
||||
from ..powermon import SimPowerSupply
|
||||
try:
|
||||
# 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
|
||||
# from ..config import Config
|
||||
@@ -173,7 +177,23 @@ def test_getNode_not_local_timeout(capsys):
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 1
|
||||
out, err = capsys.readouterr()
|
||||
assert re.match(r"Error: Timed out waiting for channels", out)
|
||||
assert re.match(r"Timed out trying to retrieve channel info, retrying", out)
|
||||
assert err == ""
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.usefixtures("reset_mt_config")
|
||||
def test_getNode_not_local_timeout_attempts(capsys):
|
||||
"""Test getNode not local, simulate timeout"""
|
||||
iface = MeshInterface(noProto=True)
|
||||
anode = MagicMock(autospec=Node)
|
||||
anode.waitForConfig.return_value = False
|
||||
with patch("meshtastic.node.Node", return_value=anode):
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
iface.getNode("bar2", requestChannelAttempts=2)
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 1
|
||||
out, err = capsys.readouterr()
|
||||
assert out == 'Timed out trying to retrieve channel info, retrying\nError: Timed out waiting for channels, giving up\n'
|
||||
assert err == ""
|
||||
|
||||
|
||||
@@ -185,7 +205,7 @@ def test_sendPosition(caplog):
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
iface.sendPosition()
|
||||
iface.close()
|
||||
assert re.search(r"p.time:", caplog.text, re.MULTILINE)
|
||||
# assert re.search(r"p.time:", caplog.text, re.MULTILINE)
|
||||
|
||||
|
||||
# TODO
|
||||
|
||||
@@ -6,7 +6,7 @@ from unittest.mock import MagicMock, patch
|
||||
|
||||
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 ..node import Node
|
||||
from ..serial_interface import SerialInterface
|
||||
@@ -231,7 +231,9 @@ def test_node(capsys):
|
||||
@pytest.mark.unit
|
||||
def test_exitSimulator(caplog):
|
||||
"""Test exitSimulator"""
|
||||
anode = Node("foo", "bar", noProto=True)
|
||||
interface = MeshInterface()
|
||||
interface.nodesByNum = {}
|
||||
anode = Node(interface, "!ba400000", noProto=True)
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
anode.exitSimulator()
|
||||
assert re.search(r"in exitSimulator", caplog.text, re.MULTILINE)
|
||||
@@ -240,7 +242,9 @@ def test_exitSimulator(caplog):
|
||||
@pytest.mark.unit
|
||||
def test_reboot(caplog):
|
||||
"""Test reboot"""
|
||||
anode = Node(MeshInterface(), 1234567890, noProto=True)
|
||||
interface = MeshInterface()
|
||||
interface.nodesByNum = {}
|
||||
anode = Node(interface, 1234567890, noProto=True)
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
anode.reboot()
|
||||
assert re.search(r"Telling node to reboot", caplog.text, re.MULTILINE)
|
||||
@@ -249,7 +253,9 @@ def test_reboot(caplog):
|
||||
@pytest.mark.unit
|
||||
def test_shutdown(caplog):
|
||||
"""Test shutdown"""
|
||||
anode = Node(MeshInterface(), 1234567890, noProto=True)
|
||||
interface = MeshInterface()
|
||||
interface.nodesByNum = {}
|
||||
anode = Node(interface, 1234567890, noProto=True)
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
anode.shutdown()
|
||||
assert re.search(r"Telling node to shutdown", caplog.text, re.MULTILINE)
|
||||
@@ -264,7 +270,7 @@ def test_setURL_empty_url(capsys):
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 1
|
||||
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 == ""
|
||||
|
||||
|
||||
@@ -298,7 +304,7 @@ def test_setURL_valid_URL_but_no_settings(capsys):
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 1
|
||||
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 == ""
|
||||
|
||||
|
||||
@@ -836,6 +842,34 @@ def test_requestChannel_localNode(caplog):
|
||||
assert re.search(r"Requesting channel 0", caplog.text, re.MULTILINE)
|
||||
assert not re.search(r"from remote node", caplog.text, re.MULTILINE)
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_requestChannels_non_localNode(caplog):
|
||||
"""Test requestChannels() with a starting index of 0"""
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
|
||||
mo.localNode.getChannelByName.return_value = None
|
||||
mo.myInfo.max_channels = 8
|
||||
anode = Node(mo, "bar", noProto=True)
|
||||
anode.partialChannels = ['0']
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
anode.requestChannels(0)
|
||||
assert re.search(f"Requesting channel 0 info from remote node", caplog.text, re.MULTILINE)
|
||||
assert anode.partialChannels == []
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_requestChannels_non_localNode_starting_index(caplog):
|
||||
"""Test requestChannels() with a starting index of non-0"""
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
with patch("meshtastic.serial_interface.SerialInterface", return_value=iface) as mo:
|
||||
mo.localNode.getChannelByName.return_value = None
|
||||
mo.myInfo.max_channels = 8
|
||||
anode = Node(mo, "bar", noProto=True)
|
||||
anode.partialChannels = ['1']
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
anode.requestChannels(3)
|
||||
assert re.search(f"Requesting channel 3 info from remote node", caplog.text, re.MULTILINE)
|
||||
# make sure it hasn't been initialized
|
||||
assert anode.partialChannels == ['1']
|
||||
|
||||
# @pytest.mark.unit
|
||||
# def test_onResponseRequestCannedMessagePluginMesagePart1(caplog):
|
||||
@@ -1392,6 +1426,60 @@ def test_requestChannel_localNode(caplog):
|
||||
# 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()
|
||||
|
||||
|
||||
# TODO
|
||||
# @pytest.mark.unitslow
|
||||
# def test_waitForConfig():
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"""Meshtastic unit tests for serial_interface.py"""
|
||||
# pylint: disable=R0917
|
||||
|
||||
import re
|
||||
from unittest.mock import mock_open, patch
|
||||
|
||||
@@ -9,7 +9,11 @@ import pytest
|
||||
from meshtastic import mt_config
|
||||
|
||||
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
|
||||
|
||||
@@ -442,6 +442,13 @@ def test_is_windows11_false_win8_1(patched_platform, patched_release):
|
||||
patched_platform.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
|
||||
@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():
|
||||
"""Test that message_to_json prints fields that aren't included in data passed in"""
|
||||
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": "" }
|
||||
assert actual == expected
|
||||
|
||||
@pytest.mark.unit
|
||||
@@ -594,3 +601,72 @@ def test_roundtrip_snake_to_camel_camel_to_snake(a_string):
|
||||
value0 = snake_to_camel(a_string=a_string)
|
||||
value1 = camel_to_snake(a_string=value0)
|
||||
assert a_string == value1, (a_string, value1)
|
||||
|
||||
@given(st.text())
|
||||
def test_fuzz_camel_to_snake(a_string):
|
||||
"""Test that camel_to_snake produces outputs with underscores for multi-word camelcase"""
|
||||
result = camel_to_snake(a_string)
|
||||
assert "_" in result or result == a_string.lower().replace("_", "")
|
||||
|
||||
@given(st.text())
|
||||
def test_fuzz_snake_to_camel(a_string):
|
||||
"""Test that snake_to_camel removes underscores"""
|
||||
result = snake_to_camel(a_string)
|
||||
assert "_" not in result or result == a_string.split("_")[0] + "".join(ele.title() for ele in a_string.split("_")[1:])
|
||||
|
||||
@given(st.text())
|
||||
def test_fuzz_stripnl(s):
|
||||
"""Test that stripnl always takes away newlines"""
|
||||
result = stripnl(s)
|
||||
assert "\n" not in result
|
||||
|
||||
@given(st.binary())
|
||||
def test_fuzz_pskToString(psk):
|
||||
"""Test that pskToString produces sane output for any bytes"""
|
||||
result = pskToString(psk)
|
||||
if len(psk) == 0:
|
||||
assert result == "unencrypted"
|
||||
elif len(psk) == 1:
|
||||
b = psk[0]
|
||||
if b == 0:
|
||||
assert result == "unencrypted"
|
||||
elif b == 1:
|
||||
assert result == "default"
|
||||
else:
|
||||
assert result == f"simple{b - 1}"
|
||||
else:
|
||||
assert result == "secret"
|
||||
|
||||
@given(st.text())
|
||||
def test_fuzz_fromStr(valstr):
|
||||
"""Test that fromStr produces mostly-useful output given any string"""
|
||||
result = fromStr(valstr)
|
||||
if valstr.startswith("0x"):
|
||||
assert isinstance(result, bytes)
|
||||
elif valstr.startswith("base64:"):
|
||||
assert isinstance(result, bytes)
|
||||
elif len(valstr) == 0:
|
||||
assert result == b''
|
||||
elif valstr.lower() in {"t", "true", "yes"}:
|
||||
assert result is True
|
||||
elif valstr.lower() in {"f", "false", "no"}:
|
||||
assert result is False
|
||||
else:
|
||||
try:
|
||||
int(valstr)
|
||||
assert isinstance(result, int)
|
||||
except ValueError:
|
||||
try:
|
||||
float(valstr)
|
||||
assert isinstance(result, float)
|
||||
except ValueError:
|
||||
assert isinstance(result, str)
|
||||
|
||||
def test_shorthex():
|
||||
"""Test the shortest hex string representations"""
|
||||
result = fromStr('0x0')
|
||||
assert result == b'\x00'
|
||||
result = fromStr('0x5')
|
||||
assert result == b'\x05'
|
||||
result = fromStr('0xffff')
|
||||
assert result == b'\xff\xff'
|
||||
|
||||
@@ -43,7 +43,7 @@ class Tunnel:
|
||||
self.message = 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
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import threading
|
||||
import time
|
||||
import traceback
|
||||
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.message import Message
|
||||
@@ -31,7 +31,7 @@ from meshtastic.version import get_active_version
|
||||
0925 Lakeview Research Saleae Logic (logic analyzer)
|
||||
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.
|
||||
0x239a RAK4631
|
||||
@@ -39,21 +39,21 @@ blacklistVids = dict.fromkeys([0x1366, 0x0483, 0x1915, 0x0925, 0x04b4])
|
||||
whitelistVids = dict.fromkeys([0x239a, 0x303a])
|
||||
|
||||
|
||||
def quoteBooleans(a_string):
|
||||
def quoteBooleans(a_string: str) -> str:
|
||||
"""Quote booleans
|
||||
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'")
|
||||
return tmp
|
||||
|
||||
|
||||
def genPSK256():
|
||||
def genPSK256() -> bytes:
|
||||
"""Generate a random preshared key"""
|
||||
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.
|
||||
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)
|
||||
|
||||
|
||||
def fromStr(valstr):
|
||||
def fromStr(valstr: str) -> Any:
|
||||
"""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)
|
||||
@@ -78,11 +78,12 @@ def fromStr(valstr):
|
||||
Args:
|
||||
valstr (string): A user provided string
|
||||
"""
|
||||
val: Any
|
||||
if len(valstr) == 0: # Treat an emptystring as an empty bytes
|
||||
val = bytes()
|
||||
elif valstr.startswith("0x"):
|
||||
# if needed convert to string with asBytes.decode('utf-8')
|
||||
val = bytes.fromhex(valstr[2:])
|
||||
val = bytes.fromhex(valstr[2:].zfill(2))
|
||||
elif valstr.startswith("base64:"):
|
||||
val = base64.b64decode(valstr[7:])
|
||||
elif valstr.lower() in {"t", "true", "yes"}:
|
||||
@@ -100,7 +101,15 @@ def fromStr(valstr):
|
||||
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"""
|
||||
if len(psk) == 0:
|
||||
return "unencrypted"
|
||||
@@ -122,12 +131,12 @@ def stripnl(s) -> str:
|
||||
return " ".join(s.split())
|
||||
|
||||
|
||||
def fixme(message):
|
||||
def fixme(message: str) -> None:
|
||||
"""Raise an exception for things that needs to be fixed"""
|
||||
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"""
|
||||
try:
|
||||
closure()
|
||||
@@ -145,7 +154,7 @@ def findPorts(eliminate_duplicates: bool=False) -> List[str]:
|
||||
all_ports = serial.tools.list_ports.comports()
|
||||
|
||||
# look for 'likely' meshtastic devices
|
||||
ports = list(
|
||||
ports: List = list(
|
||||
map(
|
||||
lambda port: port.device,
|
||||
filter(
|
||||
@@ -184,12 +193,12 @@ class dotdict(dict):
|
||||
class Timeout:
|
||||
"""Timeout class"""
|
||||
|
||||
def __init__(self, maxSecs: int=20):
|
||||
def __init__(self, maxSecs: int=20) -> None:
|
||||
self.expireTime: Union[int, float] = 0
|
||||
self.sleepInterval: float = 0.1
|
||||
self.expireTimeout: int = maxSecs
|
||||
|
||||
def reset(self):
|
||||
def reset(self) -> None:
|
||||
"""Restart the waitForSet timer"""
|
||||
self.expireTime = time.time() + self.expireTimeout
|
||||
|
||||
@@ -245,10 +254,20 @@ class Timeout:
|
||||
time.sleep(self.sleepInterval)
|
||||
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:
|
||||
"A class that records which type of acknowledgment was just received, if any."
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
"""initialize"""
|
||||
self.receivedAck = False
|
||||
self.receivedNak = False
|
||||
@@ -256,8 +275,9 @@ class Acknowledgment:
|
||||
self.receivedTraceRoute = False
|
||||
self.receivedTelemetry = False
|
||||
self.receivedPosition = False
|
||||
self.receivedWaypoint = False
|
||||
|
||||
def reset(self):
|
||||
def reset(self) -> None:
|
||||
"""reset"""
|
||||
self.receivedAck = False
|
||||
self.receivedNak = False
|
||||
@@ -265,23 +285,24 @@ class Acknowledgment:
|
||||
self.receivedTraceRoute = False
|
||||
self.receivedTelemetry = False
|
||||
self.receivedPosition = False
|
||||
self.receivedWaypoint = False
|
||||
|
||||
|
||||
class DeferredExecution:
|
||||
"""A thread that accepts closures to run, and runs them as they are received"""
|
||||
|
||||
def __init__(self, name):
|
||||
self.queue = Queue()
|
||||
def __init__(self, name) -> None:
|
||||
self.queue: Queue = Queue()
|
||||
# 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.daemon = True
|
||||
self.thread.start()
|
||||
|
||||
def queueWork(self, runnable):
|
||||
def queueWork(self, runnable) -> None:
|
||||
"""Queue up the work"""
|
||||
self.queue.put(runnable)
|
||||
|
||||
def _run(self):
|
||||
def _run(self) -> None:
|
||||
while True:
|
||||
try:
|
||||
o = self.queue.get()
|
||||
@@ -301,7 +322,7 @@ def our_exit(message, return_value=1) -> NoReturn:
|
||||
sys.exit(return_value)
|
||||
|
||||
|
||||
def support_info():
|
||||
def support_info() -> None:
|
||||
"""Print out info that helps troubleshooting of the cli."""
|
||||
print("")
|
||||
print("If having issues with meshtastic cli or python library")
|
||||
@@ -330,7 +351,7 @@ def support_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.
|
||||
Will removed nested keys.
|
||||
"""
|
||||
@@ -345,33 +366,33 @@ def remove_keys_from_dict(keys, adict):
|
||||
return adict
|
||||
|
||||
|
||||
def hexstr(barray):
|
||||
def hexstr(barray: bytes) -> str:
|
||||
"""Print a string of hex digits"""
|
||||
return ":".join(f"{x:02x}" for x in barray)
|
||||
|
||||
|
||||
def ipstr(barray):
|
||||
def ipstr(barray: bytes) -> str:
|
||||
"""Print a string of ip digits"""
|
||||
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)"""
|
||||
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
|
||||
val - base64 encoded value (ex: '/c0gFyhb'))
|
||||
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):
|
||||
val_as_bytes = base64.b64decode(val)
|
||||
val_as_bytes: bytes = base64.b64decode(val)
|
||||
return hexstr(val_as_bytes)
|
||||
return val
|
||||
|
||||
|
||||
def snake_to_camel(a_string):
|
||||
def snake_to_camel(a_string: str) -> str:
|
||||
"""convert snake_case to camelCase"""
|
||||
# split underscore using split
|
||||
temp = a_string.split("_")
|
||||
@@ -380,16 +401,16 @@ def snake_to_camel(a_string):
|
||||
return result
|
||||
|
||||
|
||||
def camel_to_snake(a_string):
|
||||
def camel_to_snake(a_string: str) -> str:
|
||||
"""convert camelCase to snake_case"""
|
||||
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"""
|
||||
system = platform.system()
|
||||
system: str = platform.system()
|
||||
# print(f'system:{system}')
|
||||
|
||||
possible_devices = set()
|
||||
@@ -447,9 +468,9 @@ def detect_supported_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"""
|
||||
need_to_install_driver = False
|
||||
need_to_install_driver: bool = False
|
||||
|
||||
if sd:
|
||||
system = platform.system()
|
||||
@@ -475,7 +496,7 @@ def detect_windows_needs_driver(sd, print_reason=False):
|
||||
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.
|
||||
|
||||
ports is a list of ports
|
||||
@@ -508,23 +529,23 @@ def eliminate_duplicate_port(ports):
|
||||
return new_ports
|
||||
|
||||
|
||||
def is_windows11():
|
||||
def is_windows11() -> bool:
|
||||
"""Detect if Windows 11"""
|
||||
is_win11 = False
|
||||
is_win11: bool = False
|
||||
if platform.system() == "Windows":
|
||||
if float(platform.release()) >= 10.0:
|
||||
patch = platform.version().split(".")[2]
|
||||
# in case they add some number suffix later, just get first 5 chars of patch
|
||||
patch = patch[:5]
|
||||
try:
|
||||
try:
|
||||
if float(platform.release()) >= 10.0:
|
||||
patch = platform.version().split(".")[2]
|
||||
# in case they add some number suffix later, just get first 5 chars of patch
|
||||
patch = patch[:5]
|
||||
if int(patch) >= 22000:
|
||||
is_win11 = True
|
||||
except Exception as e:
|
||||
print(f"problem detecting win11 e:{e}")
|
||||
except Exception as e:
|
||||
print(f"problem detecting win11 e:{e}")
|
||||
return is_win11
|
||||
|
||||
|
||||
def get_unique_vendor_ids():
|
||||
def get_unique_vendor_ids() -> Set[str]:
|
||||
"""Return a set of unique vendor ids"""
|
||||
vids = set()
|
||||
for d in supported_devices:
|
||||
@@ -533,7 +554,7 @@ def get_unique_vendor_ids():
|
||||
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"""
|
||||
sd = set()
|
||||
for d in supported_devices:
|
||||
@@ -542,11 +563,11 @@ def get_devices_with_vendor_id(vid):
|
||||
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"""
|
||||
ports = set()
|
||||
baseports = set()
|
||||
system = platform.system()
|
||||
ports: Set = set()
|
||||
baseports: Set = set()
|
||||
system: str = platform.system()
|
||||
|
||||
# figure out what possible base ports there are
|
||||
for d in sds:
|
||||
@@ -604,13 +625,13 @@ def active_ports_on_supported_devices(sds, eliminate_duplicates=False):
|
||||
for com_port in com_ports:
|
||||
ports.add(com_port)
|
||||
if eliminate_duplicates:
|
||||
ports = eliminate_duplicate_port(list(ports))
|
||||
ports.sort()
|
||||
ports = set(ports)
|
||||
portlist: List = eliminate_duplicate_port(list(ports))
|
||||
portlist.sort()
|
||||
ports = set(portlist)
|
||||
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"""
|
||||
ports = set()
|
||||
|
||||
@@ -635,20 +656,26 @@ def detect_windows_port(sd):
|
||||
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."""
|
||||
pypi_version = None
|
||||
pypi_version: Optional[str] = None
|
||||
try:
|
||||
url = "https://pypi.org/pypi/meshtastic/json"
|
||||
url: str = "https://pypi.org/pypi/meshtastic/json"
|
||||
data = requests.get(url, timeout=5).json()
|
||||
pypi_version = data["info"]["version"]
|
||||
except Exception:
|
||||
pass
|
||||
act_version = get_active_version()
|
||||
|
||||
if pypi_version is None:
|
||||
return None
|
||||
try:
|
||||
parsed_act_version = pkg_version.parse(act_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:
|
||||
return pypi_version
|
||||
|
||||
@@ -660,5 +687,8 @@ def check_if_newer_version():
|
||||
|
||||
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."""
|
||||
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
|
||||
|
||||
3462
poetry.lock
generated
3462
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
Submodule protobufs updated: 10494bf328...078ac8dfbe
@@ -1,31 +1,31 @@
|
||||
[tool.poetry]
|
||||
name = "meshtastic"
|
||||
version = "2.4.0a0"
|
||||
version = "2.6.3"
|
||||
description = "Python API & client shell for talking to Meshtastic devices"
|
||||
authors = ["Meshtastic Developers <contact@meshtastic.org>"]
|
||||
license = "GPL-3.0-only"
|
||||
readme = "README.md"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.9,<3.13" # 3.9 is needed for pandas, bleak requires a max of 3.13 for some reason
|
||||
python = "^3.9,<3.14" # 3.9 is needed for pandas, bleak requires <3.14
|
||||
pyserial = "^3.5"
|
||||
protobuf = ">=5.26.0"
|
||||
dotmap = "^1.3.30"
|
||||
pexpect = "^4.9.0"
|
||||
pyqrcode = "^1.2.1"
|
||||
protobuf = ">=4.21.12"
|
||||
tabulate = "^0.9.0"
|
||||
webencodings = "^0.5.1"
|
||||
requests = "^2.31.0"
|
||||
pyparsing = "^3.1.2"
|
||||
pyyaml = "^6.0.1"
|
||||
pypubsub = "^4.0.3"
|
||||
bleak = "^0.21.1"
|
||||
bleak = "^0.22.3"
|
||||
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 }
|
||||
pytap2 = { version = "^2.3.0", optional = true }
|
||||
dash-bootstrap-components = { version = "^1.6.0", optional = true }
|
||||
pandas = { version = "^2.2.2", optional = true }
|
||||
pandas-stubs = { version = "^2.2.2.240603", optional = true }
|
||||
wcwidth = {version = "^0.2.13", optional = true}
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
hypothesis = "^6.103.2"
|
||||
@@ -36,14 +36,13 @@ autopep8 = "^2.1.0"
|
||||
pylint = "^3.2.3"
|
||||
pyinstaller = "^6.8.0"
|
||||
mypy = "^1.10.0"
|
||||
mypy-protobuf = "^3.6.0"
|
||||
mypy-protobuf = "^3.3.0"
|
||||
types-protobuf = "^5.26.0.20240422"
|
||||
types-tabulate = "^0.9.0.20240106"
|
||||
types-requests = "^2.31.0.20240406"
|
||||
types-setuptools = "^69.5.0.20240423"
|
||||
types-pyyaml = "^6.0.12.20240311"
|
||||
pyarrow-stubs = "^10.0.1.7"
|
||||
pandas-stubs = "^2.2.2.240603"
|
||||
|
||||
[tool.poetry.group.powermon]
|
||||
optional = true
|
||||
@@ -67,6 +66,7 @@ ipywidgets = "^8.1.3"
|
||||
jupyterlab-widgets = "^3.0.11"
|
||||
|
||||
[tool.poetry.extras]
|
||||
cli = ["pyqrcode", "print-color", "dotmap", "argcomplete", "wcwidth"]
|
||||
tunnel = ["pytap2"]
|
||||
analysis = ["dash", "dash-bootstrap-components", "pandas", "pandas-stubs"]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user