Compare commits

...

91 Commits
2.5.7 ... 2.6.3

Author SHA1 Message Date
github-actions
56680f8da6 bump version to 2.6.3 2025-05-08 22:27:56 +00:00
Ian McEwen
321a960c13 protobufs: v2.6.7 2025-05-08 15:26:47 -07:00
Ian McEwen
4668852b0b Admin messages should be requesting acknowledgements 2025-05-08 15:22:27 -07:00
github-actions
c3973117c8 bump version to 2.6.2 2025-04-23 16:49:59 +00:00
Ian McEwen
d456e4ce30 protobufs: v2.6.6 2025-04-23 09:47:13 -07:00
Ben Meadors
ec78f62992 Merge pull request #763 from meshtastic/revert-753-fix-rtsdtr-windows
Revert "Work around RTS/DTR serial reset issues on Windows"
2025-04-15 16:37:23 -05:00
Ben Meadors
dfc9547ffc Revert "Work around RTS/DTR serial reset issues on Windows" 2025-04-15 16:03:33 -05:00
Ian McEwen
ee0f73a20e Merge pull request #761 from derekn/master
fixing tcp_interface 100% cpu usage bug (#709)
2025-04-15 13:56:28 -07:00
Derek Nicol
2e73fe310c fixing tcp_interface 100% cpu usage bug (#709) 2025-04-15 15:23:09 -05:00
Ian McEwen
d4bc39153a bump to 2.6.2a0 2025-04-05 23:01:43 -07:00
github-actions
2e8f823431 bump version to 2.6.1 2025-04-06 05:56:17 +00:00
Ian McEwen
675169167c protobufs: v2.6.4 2025-04-05 22:53:02 -07:00
Ian McEwen
75f8e27799 Merge pull request #749 from cdanis/fix-default-pytest
Fix pytest test collection on default install
2025-03-30 22:28:28 -07:00
Ian McEwen
f426699d2b Merge pull request #753 from dwhinham/fix-rtsdtr-windows
Work around RTS/DTR serial reset issues on Windows
2025-03-30 22:27:34 -07:00
Dale Whinham
bc1664dade Work around RTS/DTR serial reset issues on Windows
Some devices (e.g. Heltec V3.1) are reset when the RTS or DTR pins are
messed with, which means that without workarounds, Meshtastic CLI will
cause a reset with any operation that opens the serial port.

This behavior is documented in this PySerial issue:
https://github.com/pyserial/pyserial/issues/124

On Linux, we already handle this by disabling the HUPCL termios flag,
which has the effect of preventing the offending lines being toggled. On
Windows, setting the initial state of RTS and DTR before opening the
port has a similar effect.

Implement this workaround so that Meshtastic CLI can be used on Windows
with these devices.
2025-03-20 13:47:25 +00:00
Ian McEwen
32a61b0209 Make nanopb.proto stuff work right again, hopefully 2025-03-12 14:13:43 -07:00
github-actions
0c38a9eb0b bump version to 2.6.0 2025-03-10 23:18:47 +00:00
Ian McEwen
e591cc184f set 2.6 version num 2025-03-10 16:17:40 -07:00
Chris Danis
b42d33824a Fix pytest test collection on default install
As is, with a default `poetry install`, a simple `poetry pytest run`
will encouter import errors while reading the test files themselves --
which causes pytest to fatally error during test collection, meaning no
tests are run.
2025-03-07 13:16:20 -05:00
rcarteraz
ed908fc4b6 Merge pull request #748 from rcarteraz/master
update README
2025-03-03 11:44:08 -07:00
rcarteraz
3710e6e909 update README 2025-03-03 11:42:15 -07:00
Ian McEwen
faa8064ccc protobufs: v2.6.0 2025-03-02 12:14:20 -07:00
Ian McEwen
2f44351945 Merge pull request #742 from ianmcorvidae/multiset
Enable setting things from more than one configuration section with `--set`, using a configuration transaction.
2025-02-21 10:08:15 -07:00
Ian McEwen
852949575b Enable setting things from more than one configuration section with --set, using a configuration transaction. 2025-02-20 11:39:16 -07:00
github-actions
e2c9c1315e bump version to 2.5.12 2025-02-19 17:21:25 +00:00
Ian McEwen
f41ef042a9 Merge pull request #708 from mikeymakesit/add-channel
Add new channels from an add URL with the new --ch-add-url option
2025-02-19 10:18:09 -07:00
Ian McEwen
84bec5a7c4 fix up misc. lint/type/test issues, streamline, align argument names and groupings 2025-02-19 10:15:27 -07:00
Ian McEwen
985366c812 Merge pull request #710 from digitaldisarray/master
Add text message port cli option
2025-02-19 09:55:01 -07:00
Ian McEwen
3954fbd404 fix misc lint, test, type complaints from CI 2025-02-19 09:52:16 -07:00
Ian McEwen
5f174b2850 Merge pull request #731 from migillett/464/0x-prefix
464: allow for 0x node prefix values
2025-02-19 09:30:15 -07:00
Michael Gillett
23ea19c00b linter fixes following failed build 2025-02-19 11:26:49 -05:00
Ian McEwen
acc47146c9 Merge pull request #736 from dandrzejewski/master
Add optional CLI parameter to specify node info fields to show with --nodes parameter.
2025-02-19 09:26:17 -07:00
Ian McEwen
dd8803793d fix test mock 2025-02-19 09:21:51 -07:00
Ian McEwen
68ec588804 remove trailing whitespace 2025-02-19 09:15:45 -07:00
David Andrzejewski
2f48594dc3 Fix a pylint error regarding typing. 2025-02-18 22:09:37 -05:00
David Andrzejewski
c7c3c69fc3 Fix a pylint error regarding typing. 2025-02-18 22:08:26 -05:00
David Andrzejewski
53e40d5aab Fix a pylint error 2025-02-18 22:05:46 -05:00
David Andrzejewski
dd3da6a670 Merge remote-tracking branch 'origin/master' 2025-02-18 21:18:59 -05:00
David Andrzejewski
e500b399f4 Merge branch 'meshtastic:master' into master 2025-02-18 21:18:48 -05:00
David Andrzejewski
27ac28e300 Fixing indentation per project coding standards. 2025-02-18 21:18:22 -05:00
David Andrzejewski
6bc5f5e305 Fix count vs len on a list (https://github.com/meshtastic/python/pull/736#discussion_r1960099918) 2025-02-18 21:15:31 -05:00
Michael Gillett
c844e4e0fe help details for new prefix values 2025-02-18 15:25:24 -05:00
Michael Gillett
060df86bb6 Update __main__.py 2025-02-18 15:10:55 -05:00
Michael Gillett
7d87d5037e Update __main__.py 2025-02-18 15:10:26 -05:00
Michael Gillett
4ec7698d94 metavars being a PAIN 2025-02-18 15:09:59 -05:00
Michael Gillett
7cc65aa08a missed one 2025-02-18 15:06:20 -05:00
Michael Gillett
cc411ce0bb remove nargs and unneeded fstrings 2025-02-18 15:05:31 -05:00
Michael Gillett
edff956f9d specify nargs 2025-02-18 14:53:01 -05:00
Michael Gillett
bd68739158 >= 8 instead of > 8 2025-02-18 14:30:28 -05:00
Michael Gillett
530d92ead2 remove redundant f string 2025-02-18 14:24:04 -05:00
Michael Gillett
60f9dc6266 new implementation 2025-02-18 14:23:55 -05:00
Michael Gillett
f9ae021e43 remove old implementation 2025-02-18 14:23:40 -05:00
Michael Gillett
317d81c983 list -> tuple fix for pytest 2025-02-18 14:02:48 -05:00
Ian McEwen
5837bd0172 Merge pull request #734 from dudash/master
catch unhandled OSError when serial port in use
2025-02-18 09:52:03 -07:00
Ian McEwen
5487f7a791 Merge pull request #735 from tache/master
Added descriptive FileNotFoundError handler for serial device connection
2025-02-18 09:51:17 -07:00
Ian McEwen
c6d8a540eb Bump to 2.5.12a0 2025-02-18 09:43:55 -07:00
Ian McEwen
0962c9b058 protobufs: v2.5.22 2025-02-18 09:43:32 -07:00
Ian McEwen
4f98602ac2 ignore argcomplete import in main 2025-02-18 09:41:54 -07:00
David Andrzejewski
6ebddb67c0 Refactored showNodes. It now uses a lookup table to determine the human-readable names of the fields. 2025-02-15 17:18:14 -05:00
David Andrzejewski
82554a1f18 Add optional parameter to specify what fields to show with --nodes 2025-02-15 02:23:13 -05:00
tache
8c115dc636 Added descriptive FileNotFoundError handler for serial device connection
- Added a detailed error message for FileNotFoundError when the serial device is not found.
- Included troubleshooting steps for common issues.
2025-02-09 14:23:31 -05:00
dudash
e2fe359527 catch unhandled OSError when serial port in use 2025-02-08 14:51:53 -05:00
Michael Gillett
5600ce92b0 update to comments 2025-01-26 13:10:56 -05:00
Michael Gillett
efb848adf9 comments explaining logic 2025-01-26 12:58:18 -05:00
Michael Gillett
0d8646189f remove logging.info used for local debugging 2025-01-26 12:56:17 -05:00
Michael Gillett
d0023df8ca slight logic rework 2025-01-26 12:55:03 -05:00
Michael Gillett
b522abf33e update docs 2025-01-26 12:06:31 -05:00
Michael Gillett
c086b6372e Update mesh_interface.py 2025-01-26 11:58:48 -05:00
github-actions
6ec506fe3b bump version to 2.5.11 2025-01-24 17:22:13 +00:00
Ian McEwen
fc3b81dfde protobufs: v2.5.20 2025-01-24 10:19:13 -07:00
Ben Meadors
9c53ea017c Merge pull request #730 from migillett/feature/nodes-add-role
#692 feature/nodes-add-role
2025-01-23 19:07:46 -06:00
Michael Gillett
1e6625d062 feature/nodes-add-role 2025-01-21 22:31:33 -05:00
github-actions
0487ce5e1a bump version to 2.5.10 2025-01-10 17:10:16 +00:00
Ian McEwen
aac19b2ecc protobufs: v2.5.19 2025-01-10 10:06:40 -07:00
digitaldisarray
0fb72b8ad1 Only allow PRIVATE_APP custom port 2024-12-31 15:15:18 -08:00
github-actions
872fbef5d6 bump version to 2.5.9 2024-12-29 03:22:52 +00:00
Ian McEwen
ec4fbe3a59 protobufs: v2.5.18 2024-12-28 20:18:13 -07:00
Ian McEwen
6bab385380 Tweak error messaging in the onReceive function for sendtext packets 2024-12-27 10:04:36 -07:00
Ian McEwen
b8178d513a bump alpha version 2024-12-27 09:54:15 -07:00
Ian McEwen
f4c085fc50 Merge pull request #714 from loic-fejoz/feature/waypoint
Waypoint creation/move/deletion
2024-12-27 09:46:45 -07:00
Ian McEwen
57f0598082 Fix some pylint complaints 2024-12-27 09:40:17 -07:00
github-actions
55d3188408 bump version to 2.5.8 2024-12-27 12:06:45 +00:00
Ben Meadors
7b64fbb71b Merge pull request #725 from meshtastic/dependabot/pip/jinja2-3.1.5
Bump jinja2 from 3.1.4 to 3.1.5
2024-12-25 08:42:58 -06:00
dependabot[bot]
7f85eb0285 Bump jinja2 from 3.1.4 to 3.1.5
Bumps [jinja2](https://github.com/pallets/jinja) from 3.1.4 to 3.1.5.
- [Release notes](https://github.com/pallets/jinja/releases)
- [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/jinja/compare/3.1.4...3.1.5)

---
updated-dependencies:
- dependency-name: jinja2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-24 00:32:14 +00:00
Ben Meadors
d05ef17ab3 Merge pull request #724 from meshtastic/send-alert
Add sendAlert method on mesh interface
2024-12-23 10:48:49 -06:00
Ben Meadors
d161291ca4 Add sendAlert method on mesh interface 2024-12-22 09:09:54 -06:00
Ian McEwen
4e267c75b0 bump to 2.5.8a0 2024-12-21 20:49:32 -07:00
Loïc Fejoz
7cc18e9df6 fix(waypoint): Missing methods
Add missing methods callbacks regarding waypoints.
2024-12-21 10:36:36 +01:00
Loïc Fejoz
9284a848f2 feat(waypoint): Waypoint creation/deletion
Add methods to send (create or move), delete waypoint.
Add an example script to create, move, delete waypoint.
2024-12-18 17:36:58 +01:00
digitaldisarray
74c911cb75 Add text message port cli option 2024-12-06 17:54:08 -08:00
Mike Hornung
579383cd5a Add new channels from an add URL with the new --ch-add-url option 2024-12-01 23:33:47 -08:00
38 changed files with 1764 additions and 358 deletions

BIN
.github/meshtastic_logo.png vendored Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

17
.vscode/launch.json vendored
View File

@@ -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"]
}
]
}

View File

@@ -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>
[![codecov](https://codecov.io/gh/meshtastic/python/branch/master/graph/badge.svg?token=TIWPJL73KV)](https://codecov.io/gh/meshtastic/python)
![PyPI - Downloads](https://img.shields.io/pypi/dm/meshtastic)
@@ -7,17 +13,20 @@
[![Fiscal Contributors](https://opencollective.com/meshtastic/tiers/badge.svg?label=Fiscal%20Contributors&color=deeppink)](https://opencollective.com/meshtastic/)
![GPL-3.0](https://img.shields.io/badge/License-GPL%20v3-blue.svg)
</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)**
**[API Documentation](https://python.meshtastic.org)**
## 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.

View File

@@ -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
View 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()

View File

@@ -11,7 +11,7 @@ from types import ModuleType
import argparse
argcomplete: Union[None, ModuleType] = None
try:
import argcomplete
import argcomplete # type: ignore
except ImportError as e:
pass # already set to None by default above
@@ -74,7 +74,7 @@ def onReceive(packet, interface) -> None:
args
and args.sendtext
and packet["to"] == interface.myInfo.my_node_num
and d["portnum"] == portnums_pb2.PortNum.TEXT_MESSAGE_APP
and d.get("portnum", portnums_pb2.PortNum.UNKNOWN_APP) == portnums_pb2.PortNum.TEXT_MESSAGE_APP
):
interface.close() # after running command then exit
@@ -90,7 +90,7 @@ def onReceive(packet, interface) -> None:
interface.sendText(reply)
except Exception as ex:
print(f"Warning: There is no field {ex} in the packet.")
print(f"Warning: Error processing received packet: {ex}.")
def onConnection(interface, topic=pub.AUTO_TOPIC) -> None: # pylint: disable=W0613
@@ -226,7 +226,7 @@ def setPref(config, comp_name, raw_val) -> bool:
logging.debug(f"valStr:{raw_val} val:{val}")
if snake_name == "wifi_psk" and len(str(raw_val)) < 8:
print(f"Warning: network.wifi_psk must be 8 or more characters.")
print("Warning: network.wifi_psk must be 8 or more characters.")
return False
enumType = pref.enum_type
@@ -483,6 +483,7 @@ def onConnected(interface):
if checkChannel(interface, channelIndex):
print(
f"Sending text message {args.sendtext} to {args.dest} on channelIndex:{channelIndex}"
f" {'using PRIVATE_APP port' if args.private else ''}"
)
interface.sendText(
args.sendtext,
@@ -490,6 +491,7 @@ def onConnected(interface):
wantAck=True,
channelIndex=channelIndex,
onResponse=interface.getNode(args.dest, False, **getNode_kwargs).onAckNak,
portNum=portnums_pb2.PortNum.PRIVATE_APP if args.private else portnums_pb2.PortNum.TEXT_MESSAGE_APP
)
else:
meshtastic.util.our_exit(
@@ -595,6 +597,7 @@ def onConnected(interface):
# Handle the int/float/bool arguments
pref = None
fields = set()
for pref in args.set:
found = False
field = splitCompoundName(pref[0].lower())[0]
@@ -607,11 +610,19 @@ def onConnected(interface):
)
found = setPref(config, pref[0], pref[1])
if found:
fields.add(field)
break
if found:
print("Writing modified preferences to device")
node.writeConfig(field)
if len(fields) > 1:
print("Using a configuration transaction")
node.beginSettingsTransaction()
for field in fields:
print(f"Writing {field} configuration to device")
node.writeConfig(field)
if len(fields) > 1:
node.commitSettingsTransaction()
else:
if mt_config.camel_case:
print(
@@ -714,12 +725,16 @@ def onConnected(interface):
closeNow = True
export_config(interface)
if args.seturl:
if args.ch_set_url:
closeNow = True
interface.getNode(args.dest, **getNode_kwargs).setURL(args.seturl)
interface.getNode(args.dest, **getNode_kwargs).setURL(args.ch_set_url, addOnly=False)
# handle changing channels
if args.ch_add_url:
closeNow = True
interface.getNode(args.dest, **getNode_kwargs).setURL(args.ch_add_url, addOnly=True)
if args.ch_add:
channelIndex = mt_config.channel_index
if channelIndex is not None:
@@ -921,7 +936,11 @@ def onConnected(interface):
if args.dest != BROADCAST_ADDR:
print("Showing node list of a remote node is not supported.")
return
interface.showNodes()
interface.showNodes(True, args.show_fields)
if args.show_fields and not args.nodes:
print("--show-fields can only be used with --nodes")
return
if args.qr or args.qr_all:
closeNow = True
@@ -1245,6 +1264,19 @@ def common():
noProto=args.noproto,
noNodes=args.no_nodes,
)
except FileNotFoundError:
# Handle the case where the serial device is not found
message = (
f"File Not Found Error:\n"
)
message += f" The serial device at '{args.port}' was not found.\n"
message += " Please check the following:\n"
message += " 1. Is the device connected properly?\n"
message += " 2. Is the correct serial port specified?\n"
message += " 3. Are the necessary drivers installed?\n"
message += " 4. Are you using a **power-only USB cable**? A power-only cable cannot transmit data.\n"
message += " Ensure you are using a **data-capable USB cable**.\n"
meshtastic.util.our_exit(message, 1)
except PermissionError as ex:
username = os.getlogin()
message = "Permission Error:\n"
@@ -1255,6 +1287,12 @@ def common():
message += " After running that command, log out and re-login for it to take effect.\n"
message += f"Error was:{ex}"
meshtastic.util.our_exit(message)
except OSError as ex:
message = f"OS Error:\n"
message += " The serial device couldn't be opened, it might be in use by another process.\n"
message += " Please close any applications or webpages that may be using the device and try again.\n"
message += f"\nOriginal error: {ex}"
meshtastic.util.our_exit(message)
if client.devPath is None:
try:
client = meshtastic.tcp_interface.TCPInterface(
@@ -1342,7 +1380,8 @@ def addSelectionArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentParser
group.add_argument(
"--dest",
help="The destination node id for any sent commands, if not set '^all' or '^local' is assumed as appropriate",
help="The destination node id for any sent commands. If not set '^all' or '^local' is assumed."
"Use the node ID with a '!' or '0x' prefix or the node number.",
default=None,
metavar="!xxxxxxxx",
)
@@ -1387,7 +1426,7 @@ def addConfigArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentParser:
"--get",
help=(
"Get a preferences field. Use an invalid field such as '0' to get a list of all fields."
" Can use either snake_case or camelCase format. (ex: 'ls_secs' or 'lsSecs')"
" Can use either snake_case or camelCase format. (ex: 'power.ls_secs' or 'power.lsSecs')"
),
nargs=1,
action="append",
@@ -1396,7 +1435,11 @@ def addConfigArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentParser:
group.add_argument(
"--set",
help="Set a preferences field. Can use either snake_case or camelCase format. (ex: 'ls_secs' or 'lsSecs')",
help=(
"Set a preferences field. Can use either snake_case or camelCase format."
" (ex: 'power.ls_secs' or 'power.lsSecs'). May be less reliable when"
" setting properties from more than one configuration section."
),
nargs=2,
action="append",
metavar=("FIELD", "VALUE"),
@@ -1489,7 +1532,20 @@ def addConfigArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentParser:
"--set-ham", help="Set licensed Ham ID and turn off encryption", action="store"
)
group.add_argument("--seturl", help="Set a channel URL", action="store")
group.add_argument(
"--ch-set-url", "--seturl",
help="Set all channels and set LoRa config from a supplied URL",
metavar="URL",
action="store"
)
group.add_argument(
"--ch-add-url",
help="Add secondary channels and set LoRa config from a supplied URL",
metavar="URL",
default=None,
)
return parser
@@ -1627,6 +1683,13 @@ def addLocalActionArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentPars
action="store_true",
)
group.add_argument(
"--show-fields",
help="Specify fields to show (comma-separated) when using --nodes",
type=lambda s: s.split(','),
default=None
)
return parser
def addRemoteActionArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentParser:
@@ -1638,15 +1701,21 @@ def addRemoteActionArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentPar
group.add_argument(
"--sendtext",
help="Send a text message. Can specify a destination '--dest' and/or channel index '--ch-index'.",
help="Send a text message. Can specify a destination '--dest', use of PRIVATE_APP port '--private', and/or channel index '--ch-index'.",
metavar="TEXT",
)
group.add_argument(
"--private",
help="Optional argument for sending text messages to the PRIVATE_APP port. Use in combination with --sendtext.",
action="store_true"
)
group.add_argument(
"--traceroute",
help="Traceroute from connected node to a destination. "
"You need pass the destination ID as argument, like "
"this: '--traceroute !ba4bf9d0' "
"this: '--traceroute !ba4bf9d0' | '--traceroute 0xba4bf9d0'"
"Only nodes with a shared channel can be traced.",
metavar="!xxxxxxxx",
)
@@ -1727,27 +1796,32 @@ def addRemoteAdminArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentPars
group.add_argument(
"--remove-node",
help="Tell the destination node to remove a specific node from its DB, by node number or ID",
help="Tell the destination node to remove a specific node from its NodeDB. "
"Use the node ID with a '!' or '0x' prefix or the node number.",
metavar="!xxxxxxxx"
)
group.add_argument(
"--set-favorite-node",
help="Tell the destination node to set the specified node to be favorited on the NodeDB on the devicein its DB, by number or ID",
help="Tell the destination node to set the specified node to be favorited on the NodeDB. "
"Use the node ID with a '!' or '0x' prefix or the node number.",
metavar="!xxxxxxxx"
)
group.add_argument(
"--remove-favorite-node",
help="Tell the destination node to set the specified node to be un-favorited on the NodeDB on the device, by number or ID",
help="Tell the destination node to set the specified node to be un-favorited on the NodeDB. "
"Use the node ID with a '!' or '0x' prefix or the node number.",
metavar="!xxxxxxxx"
)
group.add_argument(
"--set-ignored-node",
help="Tell the destination node to set the specified node to be ignored on the NodeDB on the devicein its DB, by number or ID",
help="Tell the destination node to set the specified node to be ignored on the NodeDB. "
"Use the node ID with a '!' or '0x' prefix or the node number.",
metavar="!xxxxxxxx"
)
group.add_argument(
"--remove-ignored-node",
help="Tell the destination node to set the specified node to be un-ignored on the NodeDB on the device, by number or ID",
help="Tell the destination node to set the specified node to be un-ignored on the NodeDB. "
"Use the node ID with a '!' or '0x' prefix or the node number.",
metavar="!xxxxxxxx"
)
group.add_argument(

View File

@@ -5,7 +5,9 @@
import collections
import json
import logging
import math
import random
import secrets
import sys
import threading
import time
@@ -220,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."""
@@ -244,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}")
@@ -252,65 +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"),
"Pubkey": user.get("publicKey", "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": node.get("hopsAway", "?"),
"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):
@@ -342,7 +395,7 @@ class MeshInterface: # pylint: disable=R0902
if new_index != last_index:
retries_left = requestChannelAttempts - 1
if retries_left <= 0:
our_exit(f"Error: Timed out waiting for channels, giving up")
our_exit("Error: Timed out waiting for channels, giving up")
print("Timed out trying to retrieve channel info, retrying")
n.requestChannels(startingIndex=new_index)
last_index = new_index
@@ -358,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.
@@ -368,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.
@@ -382,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,
@@ -402,6 +490,7 @@ class MeshInterface: # pylint: disable=R0902
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
@@ -453,6 +542,8 @@ 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}")
@@ -700,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,
@@ -745,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)
@@ -780,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)}")
@@ -824,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:
@@ -963,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)}")

View File

@@ -337,14 +337,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
@@ -361,20 +366,36 @@ 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)
@@ -962,7 +983,7 @@ class Node:
p,
self.nodeNum,
portNum=portnums_pb2.PortNum.ADMIN_APP,
wantAck=False,
wantAck=True,
wantResponse=wantResponse,
onResponse=onResponse,
channelIndex=adminIndex,

View File

File diff suppressed because one or more lines are too long

View File

@@ -74,7 +74,9 @@ class AdminMessage(google.protobuf.message.Message):
TODO: REPLACE
"""
SESSIONKEY_CONFIG: AdminMessage._ConfigType.ValueType # 8
""""""
"""
Session key config
"""
DEVICEUI_CONFIG: AdminMessage._ConfigType.ValueType # 9
"""
device-ui config
@@ -118,7 +120,9 @@ class AdminMessage(google.protobuf.message.Message):
TODO: REPLACE
"""
SESSIONKEY_CONFIG: AdminMessage.ConfigType.ValueType # 8
""""""
"""
Session key config
"""
DEVICEUI_CONFIG: AdminMessage.ConfigType.ValueType # 9
"""
device-ui config
@@ -241,6 +245,31 @@ 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
@@ -264,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
@@ -354,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.
@@ -554,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 = ...,
@@ -581,9 +628,9 @@ class AdminMessage(google.protobuf.message.Message):
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_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_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", "set_canned_message_module_messages", b"set_canned_message_module_messages", "set_channel", b"set_channel", "set_config", b"set_config", "set_favorite_node", b"set_favorite_node", "set_fixed_position", b"set_fixed_position", "set_ham_mode", b"set_ham_mode", "set_ignored_node", b"set_ignored_node", "set_module_config", b"set_module_config", "set_owner", b"set_owner", "set_ringtone_message", b"set_ringtone_message", "set_scale", b"set_scale", "set_time_only", b"set_time_only", "shutdown_seconds", b"shutdown_seconds", "store_ui_config", b"store_ui_config"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["begin_edit_settings", b"begin_edit_settings", "commit_edit_settings", b"commit_edit_settings", "delete_file_request", b"delete_file_request", "enter_dfu_mode_request", b"enter_dfu_mode_request", "exit_simulator", b"exit_simulator", "factory_reset_config", b"factory_reset_config", "factory_reset_device", b"factory_reset_device", "get_canned_message_module_messages_request", b"get_canned_message_module_messages_request", "get_canned_message_module_messages_response", b"get_canned_message_module_messages_response", "get_channel_request", b"get_channel_request", "get_channel_response", b"get_channel_response", "get_config_request", b"get_config_request", "get_config_response", b"get_config_response", "get_device_connection_status_request", b"get_device_connection_status_request", "get_device_connection_status_response", b"get_device_connection_status_response", "get_device_metadata_request", b"get_device_metadata_request", "get_device_metadata_response", b"get_device_metadata_response", "get_module_config_request", b"get_module_config_request", "get_module_config_response", b"get_module_config_response", "get_node_remote_hardware_pins_request", b"get_node_remote_hardware_pins_request", "get_node_remote_hardware_pins_response", b"get_node_remote_hardware_pins_response", "get_owner_request", b"get_owner_request", "get_owner_response", b"get_owner_response", "get_ringtone_request", b"get_ringtone_request", "get_ringtone_response", b"get_ringtone_response", "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_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", "session_passkey", b"session_passkey", "set_canned_message_module_messages", b"set_canned_message_module_messages", "set_channel", b"set_channel", "set_config", b"set_config", "set_favorite_node", b"set_favorite_node", "set_fixed_position", b"set_fixed_position", "set_ham_mode", b"set_ham_mode", "set_ignored_node", b"set_ignored_node", "set_module_config", b"set_module_config", "set_owner", b"set_owner", "set_ringtone_message", b"set_ringtone_message", "set_scale", b"set_scale", "set_time_only", b"set_time_only", "shutdown_seconds", b"shutdown_seconds", "store_ui_config", b"store_ui_config"]) -> None: ...
def WhichOneof(self, oneof_group: typing.Literal["payload_variant", b"payload_variant"]) -> typing.Literal["get_channel_request", "get_channel_response", "get_owner_request", "get_owner_response", "get_config_request", "get_config_response", "get_module_config_request", "get_module_config_response", "get_canned_message_module_messages_request", "get_canned_message_module_messages_response", "get_device_metadata_request", "get_device_metadata_response", "get_ringtone_request", "get_ringtone_response", "get_device_connection_status_request", "get_device_connection_status_response", "set_ham_mode", "get_node_remote_hardware_pins_request", "get_node_remote_hardware_pins_response", "enter_dfu_mode_request", "delete_file_request", "set_scale", "set_owner", "set_channel", "set_config", "set_module_config", "set_canned_message_module_messages", "set_ringtone_message", "remove_by_nodenum", "set_favorite_node", "remove_favorite_node", "set_fixed_position", "remove_fixed_position", "set_time_only", "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: ...
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

View File

File diff suppressed because one or more lines are too long

View File

@@ -108,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):
"""
@@ -184,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)
@@ -599,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
"""
@@ -693,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
@@ -735,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)
@@ -750,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
"""
@@ -764,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:
"""
@@ -781,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):
@@ -905,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):
"""
@@ -927,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)
@@ -1067,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
@@ -1114,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,
*,
@@ -1128,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):

View File

@@ -13,7 +13,7 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n#meshtastic/protobuf/device_ui.proto\x12\x13meshtastic.protobuf\"\xbf\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\"\x96\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\"~\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\x05Theme\x12\x08\n\x04\x44\x41RK\x10\x00\x12\t\n\x05LIGHT\x10\x01\x12\x07\n\x03RED\x10\x02*\xfc\x01\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\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')
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)
@@ -21,14 +21,18 @@ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.device_
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=791
_globals['_THEME']._serialized_end=828
_globals['_LANGUAGE']._serialized_start=831
_globals['_LANGUAGE']._serialized_end=1083
_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=508
_globals['_NODEFILTER']._serialized_start=511
_globals['_NODEFILTER']._serialized_end=661
_globals['_NODEHIGHLIGHT']._serialized_start=663
_globals['_NODEHIGHLIGHT']._serialized_end=789
_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)

View File

@@ -118,6 +118,14 @@ class _LanguageEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumT
"""
Norwegian
"""
SLOVENIAN: _Language.ValueType # 15
"""
Slovenian
"""
UKRAINIAN: _Language.ValueType # 16
"""
Ukrainian
"""
SIMPLIFIED_CHINESE: _Language.ValueType # 30
"""
Simplified Chinese (experimental)
@@ -192,6 +200,14 @@ NORWEGIAN: Language.ValueType # 14
"""
Norwegian
"""
SLOVENIAN: Language.ValueType # 15
"""
Slovenian
"""
UKRAINIAN: Language.ValueType # 16
"""
Ukrainian
"""
SIMPLIFIED_CHINESE: Language.ValueType # 30
"""
Simplified Chinese (experimental)
@@ -224,6 +240,7 @@ class DeviceUIConfig(google.protobuf.message.Message):
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.
@@ -272,6 +289,12 @@ class DeviceUIConfig(google.protobuf.message.Message):
Node list highlightening
"""
@property
def map_data(self) -> global___Map:
"""
Map related data
"""
def __init__(
self,
*,
@@ -289,9 +312,10 @@ class DeviceUIConfig(google.protobuf.message.Message):
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["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", "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: ...
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
@@ -305,6 +329,7 @@ class NodeFilter(google.protobuf.message.Message):
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
@@ -329,6 +354,10 @@ class NodeFilter(google.protobuf.message.Message):
"""
Filter nodes by matching name string
"""
channel: builtins.int
"""
Filter based on channel
"""
def __init__(
self,
*,
@@ -338,8 +367,9 @@ class NodeFilter(google.protobuf.message.Message):
hops_away: builtins.int = ...,
position_switch: builtins.bool = ...,
node_name: builtins.str = ...,
channel: builtins.int = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["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: ...
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
@@ -384,3 +414,66 @@ class NodeHighlight(google.protobuf.message.Message):
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

View File

@@ -15,10 +15,11 @@ from meshtastic.protobuf import channel_pb2 as meshtastic_dot_protobuf_dot_chann
from meshtastic.protobuf import mesh_pb2 as meshtastic_dot_protobuf_dot_mesh__pb2
from meshtastic.protobuf import telemetry_pb2 as meshtastic_dot_protobuf_dot_telemetry__pb2
from meshtastic.protobuf import config_pb2 as meshtastic_dot_protobuf_dot_config__pb2
import nanopb_pb2 as nanopb__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\x1emeshtastic/protobuf/mesh.proto\x1a#meshtastic/protobuf/telemetry.proto\x1a meshtastic/protobuf/config.proto\x1a\x0cnanopb.proto\"\x99\x01\n\x0cPositionLite\x12\x12\n\nlatitude_i\x18\x01 \x01(\x0f\x12\x13\n\x0blongitude_i\x18\x02 \x01(\x0f\x12\x10\n\x08\x61ltitude\x18\x03 \x01(\x05\x12\x0c\n\x04time\x18\x04 \x01(\x07\x12@\n\x0flocation_source\x18\x05 \x01(\x0e\x32\'.meshtastic.protobuf.Position.LocSource\"\xe2\x01\n\x08UserLite\x12\x13\n\x07macaddr\x18\x01 \x01(\x0c\x42\x02\x18\x01\x12\x11\n\tlong_name\x18\x02 \x01(\t\x12\x12\n\nshort_name\x18\x03 \x01(\t\x12\x34\n\x08hw_model\x18\x04 \x01(\x0e\x32\".meshtastic.protobuf.HardwareModel\x12\x13\n\x0bis_licensed\x18\x05 \x01(\x08\x12;\n\x04role\x18\x06 \x01(\x0e\x32-.meshtastic.protobuf.Config.DeviceConfig.Role\x12\x12\n\npublic_key\x18\x07 \x01(\x0c\"\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\"\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(\rBm\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)
@@ -30,16 +31,22 @@ if _descriptor._USE_C_DESCRIPTORS == False:
_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['_POSITIONLITE']._serialized_start=214
_globals['_POSITIONLITE']._serialized_end=367
_globals['_USERLITE']._serialized_start=370
_globals['_USERLITE']._serialized_end=596
_globals['_NODEINFOLITE']._serialized_start=599
_globals['_NODEINFOLITE']._serialized_end=949
_globals['_DEVICESTATE']._serialized_start=952
_globals['_DEVICESTATE']._serialized_end=1466
_globals['_CHANNELFILE']._serialized_start=1468
_globals['_CHANNELFILE']._serialized_end=1546
_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)

View File

@@ -10,6 +10,7 @@ import google.protobuf.internal.containers
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 typing
@@ -245,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
@@ -260,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:
@@ -302,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,
*,
@@ -320,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):
"""
@@ -358,3 +380,64 @@ class ChannelFile(google.protobuf.message.Message):
def ClearField(self, field_name: typing.Literal["channels", b"channels", "version", b"version"]) -> None: ...
global___ChannelFile = ChannelFile
@typing.final
class BackupPreferences(google.protobuf.message.Message):
"""
The on-disk backup of the node's preferences
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
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 version of the backup
"""
timestamp: builtins.int
"""
The timestamp of the backup (if node has time)
"""
@property
def config(self) -> meshtastic.protobuf.localonly_pb2.LocalConfig:
"""
The node's configuration
"""
@property
def module_config(self) -> meshtastic.protobuf.localonly_pb2.LocalModuleConfig:
"""
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,
*,
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["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___BackupPreferences = BackupPreferences

30
meshtastic/protobuf/interdevice_pb2.py generated Normal file
View 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
View 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

View File

File diff suppressed because one or more lines are too long

View File

@@ -295,7 +295,7 @@ class _HardwareModelEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._
"""
TWC_MESH_V4: _HardwareModel.ValueType # 62
"""
TWC_MESH_V4
TWC_MESH_V4
Adafruit NRF52840 feather express with SX1262, SSD1306 OLED and NEO6M GPS
"""
NRF52_PROMICRO_DIY: _HardwareModel.ValueType # 63
@@ -397,6 +397,50 @@ class _HardwareModelEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._
Mesh-Tab, esp32 based
https://github.com/valzzu/Mesh-Tab
"""
MESHLINK: _HardwareModel.ValueType # 87
"""
MeshLink board developed by LoraItalia. NRF52840, eByte E22900M22S (Will also come with other frequencies), 25w MPPT solar charger (5v,12v,18v selectable), support for gps, buzzer, oled or e-ink display, 10 gpios, hardware watchdog
https://www.loraitalia.it
"""
XIAO_NRF52_KIT: _HardwareModel.ValueType # 88
"""
Seeed XIAO nRF52840 + Wio SX1262 kit
"""
THINKNODE_M1: _HardwareModel.ValueType # 89
"""
Elecrow ThinkNode M1 & M2
https://www.elecrow.com/wiki/ThinkNode-M1_Transceiver_Device(Meshtastic)_Power_By_nRF52840.html
https://www.elecrow.com/wiki/ThinkNode-M2_Transceiver_Device(Meshtastic)_Power_By_NRF52840.html (this actually uses ESP32-S3)
"""
THINKNODE_M2: _HardwareModel.ValueType # 90
T_ETH_ELITE: _HardwareModel.ValueType # 91
"""
Lilygo T-ETH-Elite
"""
HELTEC_SENSOR_HUB: _HardwareModel.ValueType # 92
"""
Heltec HRI-3621 industrial probe
"""
RESERVED_FRIED_CHICKEN: _HardwareModel.ValueType # 93
"""
Reserved Fried Chicken ID for future use
"""
HELTEC_MESH_POCKET: _HardwareModel.ValueType # 94
"""
Heltec Magnetic Power Bank with Meshtastic compatible
"""
SEEED_SOLAR_NODE: _HardwareModel.ValueType # 95
"""
Seeed Solar Node
"""
NOMADSTAR_METEOR_PRO: _HardwareModel.ValueType # 96
"""
NomadStar Meteor Pro https://nomadstar.ch/
"""
CROWPANEL: _HardwareModel.ValueType # 97
"""
Elecrow CrowPanel Advance models, ESP32-S3 and TFT with SX1262 radio plugin
"""
PRIVATE_HW: _HardwareModel.ValueType # 255
"""
------------------------------------------------------------------------------------------------------------------------------------------
@@ -675,7 +719,7 @@ CDEBYTE EoRa-S3 board using their own MM modules, clone of LILYGO T3S3
"""
TWC_MESH_V4: HardwareModel.ValueType # 62
"""
TWC_MESH_V4
TWC_MESH_V4
Adafruit NRF52840 feather express with SX1262, SSD1306 OLED and NEO6M GPS
"""
NRF52_PROMICRO_DIY: HardwareModel.ValueType # 63
@@ -777,6 +821,50 @@ MESH_TAB: HardwareModel.ValueType # 86
Mesh-Tab, esp32 based
https://github.com/valzzu/Mesh-Tab
"""
MESHLINK: HardwareModel.ValueType # 87
"""
MeshLink board developed by LoraItalia. NRF52840, eByte E22900M22S (Will also come with other frequencies), 25w MPPT solar charger (5v,12v,18v selectable), support for gps, buzzer, oled or e-ink display, 10 gpios, hardware watchdog
https://www.loraitalia.it
"""
XIAO_NRF52_KIT: HardwareModel.ValueType # 88
"""
Seeed XIAO nRF52840 + Wio SX1262 kit
"""
THINKNODE_M1: HardwareModel.ValueType # 89
"""
Elecrow ThinkNode M1 & M2
https://www.elecrow.com/wiki/ThinkNode-M1_Transceiver_Device(Meshtastic)_Power_By_nRF52840.html
https://www.elecrow.com/wiki/ThinkNode-M2_Transceiver_Device(Meshtastic)_Power_By_NRF52840.html (this actually uses ESP32-S3)
"""
THINKNODE_M2: HardwareModel.ValueType # 90
T_ETH_ELITE: HardwareModel.ValueType # 91
"""
Lilygo T-ETH-Elite
"""
HELTEC_SENSOR_HUB: HardwareModel.ValueType # 92
"""
Heltec HRI-3621 industrial probe
"""
RESERVED_FRIED_CHICKEN: HardwareModel.ValueType # 93
"""
Reserved Fried Chicken ID for future use
"""
HELTEC_MESH_POCKET: HardwareModel.ValueType # 94
"""
Heltec Magnetic Power Bank with Meshtastic compatible
"""
SEEED_SOLAR_NODE: HardwareModel.ValueType # 95
"""
Seeed Solar Node
"""
NOMADSTAR_METEOR_PRO: HardwareModel.ValueType # 96
"""
NomadStar Meteor Pro https://nomadstar.ch/
"""
CROWPANEL: HardwareModel.ValueType # 97
"""
Elecrow CrowPanel Advance models, ESP32-S3 and TFT with SX1262 radio plugin
"""
PRIVATE_HW: HardwareModel.ValueType # 255
"""
------------------------------------------------------------------------------------------------------------------------------------------
@@ -1020,6 +1108,14 @@ class _ExcludedModulesEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper
"""
Paxcounter module
"""
BLUETOOTH_CONFIG: _ExcludedModules.ValueType # 8192
"""
Bluetooth config (not technically a module, but used to indicate bluetooth capabilities)
"""
NETWORK_CONFIG: _ExcludedModules.ValueType # 16384
"""
Network config (not technically a module, but used to indicate network capabilities)
"""
class ExcludedModules(_ExcludedModules, metaclass=_ExcludedModulesEnumTypeWrapper):
"""
@@ -1084,6 +1180,14 @@ PAXCOUNTER_CONFIG: ExcludedModules.ValueType # 4096
"""
Paxcounter module
"""
BLUETOOTH_CONFIG: ExcludedModules.ValueType # 8192
"""
Bluetooth config (not technically a module, but used to indicate bluetooth capabilities)
"""
NETWORK_CONFIG: ExcludedModules.ValueType # 16384
"""
Network config (not technically a module, but used to indicate network capabilities)
"""
global___ExcludedModules = ExcludedModules
@typing.final
@@ -2083,6 +2187,7 @@ class MeshPacket(google.protobuf.message.Message):
PKI_ENCRYPTED_FIELD_NUMBER: builtins.int
NEXT_HOP_FIELD_NUMBER: builtins.int
RELAY_NODE_FIELD_NUMBER: builtins.int
TX_AFTER_FIELD_NUMBER: builtins.int
to: builtins.int
"""
The (immediate) destination for this packet
@@ -2176,7 +2281,7 @@ class MeshPacket(google.protobuf.message.Message):
"""
next_hop: builtins.int
"""
Last byte of the node number of the node that should be used as the next hop in routing.
Last byte of the node number of the node that should be used as the next hop in routing.
Set by the firmware internally, clients are not supposed to set this.
"""
relay_node: builtins.int
@@ -2184,6 +2289,12 @@ class MeshPacket(google.protobuf.message.Message):
Last byte of the node number of the node that will relay/relayed this packet.
Set by the firmware internally, clients are not supposed to set this.
"""
tx_after: builtins.int
"""
*Never* sent over the radio links.
Timestamp after which this packet may be sent.
Set by the firmware internally, clients are not supposed to set this.
"""
@property
def decoded(self) -> global___Data:
"""
@@ -2211,9 +2322,10 @@ class MeshPacket(google.protobuf.message.Message):
pki_encrypted: builtins.bool = ...,
next_hop: builtins.int = ...,
relay_node: builtins.int = ...,
tx_after: builtins.int = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["decoded", b"decoded", "encrypted", b"encrypted", "payload_variant", b"payload_variant"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["channel", b"channel", "decoded", b"decoded", "delayed", b"delayed", "encrypted", b"encrypted", "from", b"from", "hop_limit", b"hop_limit", "hop_start", b"hop_start", "id", b"id", "next_hop", b"next_hop", "payload_variant", b"payload_variant", "pki_encrypted", b"pki_encrypted", "priority", b"priority", "public_key", b"public_key", "relay_node", b"relay_node", "rx_rssi", b"rx_rssi", "rx_snr", b"rx_snr", "rx_time", b"rx_time", "to", b"to", "via_mqtt", b"via_mqtt", "want_ack", b"want_ack"]) -> None: ...
def ClearField(self, field_name: typing.Literal["channel", b"channel", "decoded", b"decoded", "delayed", b"delayed", "encrypted", b"encrypted", "from", b"from", "hop_limit", b"hop_limit", "hop_start", b"hop_start", "id", b"id", "next_hop", b"next_hop", "payload_variant", b"payload_variant", "pki_encrypted", b"pki_encrypted", "priority", b"priority", "public_key", b"public_key", "relay_node", b"relay_node", "rx_rssi", b"rx_rssi", "rx_snr", b"rx_snr", "rx_time", b"rx_time", "to", b"to", "tx_after", b"tx_after", "via_mqtt", b"via_mqtt", "want_ack", b"want_ack"]) -> None: ...
def WhichOneof(self, oneof_group: typing.Literal["payload_variant", b"payload_variant"]) -> typing.Literal["decoded", "encrypted"] | None: ...
global___MeshPacket = MeshPacket

View File

File diff suppressed because one or more lines are too long

View File

@@ -554,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):
"""
@@ -569,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
@@ -927,7 +935,7 @@ class ModuleConfig(google.protobuf.message.Message):
@typing.final
class CannedMessageConfig(google.protobuf.message.Message):
"""
TODO: REPLACE
Canned Messages Module Config
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor

35
meshtastic/protobuf/nanopb_pb2.py generated Normal file
View 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
View 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]

View File

@@ -13,7 +13,7 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\"meshtastic/protobuf/portnums.proto\x12\x13meshtastic.protobuf*\xb1\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\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=621
_globals['_PORTNUM']._serialized_end=647
# @@protoc_insertion_point(module_scope)

View File

@@ -179,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.
@@ -368,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.

View File

File diff suppressed because one or more lines are too long

View File

@@ -163,6 +163,18 @@ class _TelemetrySensorTypeEnumTypeWrapper(google.protobuf.internal.enum_type_wra
"""
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):
"""
@@ -309,6 +321,18 @@ 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
@@ -394,6 +418,10 @@ class EnvironmentMetrics(google.protobuf.message.Message):
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
@@ -468,6 +496,22 @@ class EnvironmentMetrics(google.protobuf.message.Message):
"""
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,
*,
@@ -489,9 +533,13 @@ class EnvironmentMetrics(google.protobuf.message.Message):
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 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", "_relative_humidity", b"_relative_humidity", "_temperature", b"_temperature", "_uv_lux", b"_uv_lux", "_voltage", b"_voltage", "_weight", b"_weight", "_white_lux", b"_white_lux", "_wind_direction", b"_wind_direction", "_wind_gust", b"_wind_gust", "_wind_lull", b"_wind_lull", "_wind_speed", b"_wind_speed", "barometric_pressure", b"barometric_pressure", "current", b"current", "distance", b"distance", "gas_resistance", b"gas_resistance", "iaq", b"iaq", "ir_lux", b"ir_lux", "lux", b"lux", "radiation", b"radiation", "relative_humidity", b"relative_humidity", "temperature", b"temperature", "uv_lux", b"uv_lux", "voltage", b"voltage", "weight", b"weight", "white_lux", b"white_lux", "wind_direction", b"wind_direction", "wind_gust", b"wind_gust", "wind_lull", b"wind_lull", "wind_speed", b"wind_speed"]) -> builtins.bool: ...
def 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", "_relative_humidity", b"_relative_humidity", "_temperature", b"_temperature", "_uv_lux", b"_uv_lux", "_voltage", b"_voltage", "_weight", b"_weight", "_white_lux", b"_white_lux", "_wind_direction", b"_wind_direction", "_wind_gust", b"_wind_gust", "_wind_lull", b"_wind_lull", "_wind_speed", b"_wind_speed", "barometric_pressure", b"barometric_pressure", "current", b"current", "distance", b"distance", "gas_resistance", b"gas_resistance", "iaq", b"iaq", "ir_lux", b"ir_lux", "lux", b"lux", "radiation", b"radiation", "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
@@ -509,8 +557,16 @@ class EnvironmentMetrics(google.protobuf.message.Message):
@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: ...
@@ -667,7 +723,7 @@ class AirQualityMetrics(google.protobuf.message.Message):
"""
co2: builtins.int
"""
10.0um Particle Count
CO2 concentration in ppm
"""
def __init__(
self,

View File

@@ -1,9 +1,11 @@
"""TCPInterface class for interfacing with http endpoint
"""
# pylint: disable=R0917
import contextlib
import logging
import socket
from typing import Optional, cast
import time
from typing import Optional
from meshtastic.stream_interface import StreamInterface
@@ -35,52 +37,63 @@ class TCPInterface(StreamInterface):
self.socket: Optional[socket.socket] = None
if connectNow:
logging.debug(f"Connecting to {hostname}") # type: ignore[str-bytes-safe]
server_address: tuple[str, int] = (hostname, portNumber)
sock: Optional[socket.socket] = socket.create_connection(server_address)
self.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) -> None:
"""Shutdown the socket.
Note: Broke out this line so the exception could be unit tested.
"""
if self.socket: #mian: please check that this should be "if self.socket:"
cast(socket.socket, self.socket).shutdown(socket.SHUT_RDWR)
if self.socket is not None:
self.socket.shutdown(socket.SHUT_RDWR)
def myConnect(self) -> None:
"""Connect to socket"""
server_address: tuple[str, int] = (self.hostname, self.portNumber)
sock: Optional[socket.socket] = socket.create_connection(server_address)
self.socket = sock
logging.debug(f"Connecting to {self.hostname}") # type: ignore[str-bytes-safe]
server_address = (self.hostname, self.portNumber)
self.socket = socket.create_connection(server_address)
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: bool = True
if not self.socket is None:
try:
self._wantExit = True
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()
self.socket = None
def _writeBytes(self, b: bytes) -> None:
"""Write an array of bytes to our stream and flush"""
if self.socket:
if self.socket is not None:
self.socket.send(b)
def _readBytes(self, length) -> Optional[bytes]:
"""Read an array of bytes from our stream"""
if self.socket:
return self.socket.recv(length)
else:
return None
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

View File

@@ -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

View File

@@ -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
@@ -1608,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 == ""

View File

@@ -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

View File

@@ -270,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 == ""
@@ -304,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 == ""

View File

@@ -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

View File

@@ -254,6 +254,16 @@ 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."
@@ -265,6 +275,7 @@ class Acknowledgment:
self.receivedTraceRoute = False
self.receivedTelemetry = False
self.receivedPosition = False
self.receivedWaypoint = False
def reset(self) -> None:
"""reset"""
@@ -274,6 +285,7 @@ class Acknowledgment:
self.receivedTraceRoute = False
self.receivedTelemetry = False
self.receivedPosition = False
self.receivedWaypoint = False
class DeferredExecution:

8
poetry.lock generated
View File

@@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand.
[[package]]
name = "altgraph"
@@ -1459,13 +1459,13 @@ testing = ["Django", "attrs", "colorama", "docopt", "pytest (<9.0.0)"]
[[package]]
name = "jinja2"
version = "3.1.4"
version = "3.1.5"
description = "A very fast and expressive template engine."
optional = false
python-versions = ">=3.7"
files = [
{file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"},
{file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"},
{file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"},
{file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"},
]
[package.dependencies]

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "meshtastic"
version = "2.5.7"
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"