mirror of
https://github.com/meshtastic/python.git
synced 2025-12-26 01:17:51 -05:00
Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0738e5ec6d | ||
|
|
5537778b64 | ||
|
|
341d8e0cec | ||
|
|
9b5943192d | ||
|
|
bf56521a53 | ||
|
|
16a1af6a13 | ||
|
|
b8640666d7 | ||
|
|
0528a6fb3b | ||
|
|
5511871442 | ||
|
|
486e13a93b | ||
|
|
759cafb817 | ||
|
|
bd788ae303 | ||
|
|
bb8a0d987f | ||
|
|
92cc84e692 | ||
|
|
03abaf6059 | ||
|
|
6bed30e175 | ||
|
|
9f2cc28fef | ||
|
|
fdd5b866b5 | ||
|
|
4ebb928400 | ||
|
|
4522a8a7b0 | ||
|
|
14813e5c76 | ||
|
|
c67d299984 | ||
|
|
d1efe39c59 | ||
|
|
079c8c6a24 | ||
|
|
fbcdab37ed | ||
|
|
83359a9cae | ||
|
|
67636c4ce2 | ||
|
|
fdf594492c | ||
|
|
8d6827dd23 | ||
|
|
a1ffb459f8 | ||
|
|
df8ea85873 | ||
|
|
10c2e753f5 | ||
|
|
769c99ec7d | ||
|
|
1a8778022f | ||
|
|
b7e23ab762 | ||
|
|
9fbde7b85a | ||
|
|
17ab557f81 | ||
|
|
8271997279 | ||
|
|
1c9af1f002 | ||
|
|
9a4feecea8 | ||
|
|
90c218daa7 | ||
|
|
a067c9295e | ||
|
|
48fe844e12 | ||
|
|
1a9e728dee | ||
|
|
34736bd246 | ||
|
|
193b8bcfb5 | ||
|
|
3321d8454a | ||
|
|
22f2168bfd | ||
|
|
2bf72523e9 | ||
|
|
658ecb60dc | ||
|
|
129f68ec14 | ||
|
|
281ff788f3 | ||
|
|
70069323fc | ||
|
|
4721bc5adf | ||
|
|
bc67546019 | ||
|
|
dc35ffa12e | ||
|
|
0a8a193081 |
82
.github/workflows/release.yml
vendored
82
.github/workflows/release.yml
vendored
@@ -74,51 +74,51 @@ jobs:
|
||||
user: __token__
|
||||
password: ${{ secrets.PYPI_API_TOKEN }}
|
||||
|
||||
build-and-publish-mac:
|
||||
runs-on: macos-latest
|
||||
needs: release_create
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ needs.release_create.outputs.new_sha }}
|
||||
# build-and-publish-mac:
|
||||
# runs-on: macos-latest
|
||||
# needs: release_create
|
||||
# steps:
|
||||
# - name: Checkout
|
||||
# uses: actions/checkout@v3
|
||||
# with:
|
||||
# ref: ${{ needs.release_create.outputs.new_sha }}
|
||||
|
||||
- name: Set up Python 3.9
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.9
|
||||
# - name: Set up Python 3.9
|
||||
# uses: actions/setup-python@v2
|
||||
# with:
|
||||
# python-version: 3.9
|
||||
|
||||
- name: Setup code signing
|
||||
env:
|
||||
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
|
||||
MACOS_CERTIFICATE_PWD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
|
||||
MACOS_KEYCHAIN_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
|
||||
run: |
|
||||
echo $MACOS_CERTIFICATE | base64 --decode > certificate.p12
|
||||
security create-keychain -p "$MACOS_KEYCHAIN_PASSWORD" meshtastic.keychain
|
||||
security default-keychain -s meshtastic.keychain
|
||||
security unlock-keychain -p "$MACOS_KEYCHAIN_PASSWORD" meshtastic.keychain
|
||||
security import certificate.p12 -k meshtastic.keychain -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_KEYCHAIN_PASSWORD" meshtastic.keychain
|
||||
# - name: Setup code signing
|
||||
# env:
|
||||
# MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
|
||||
# MACOS_CERTIFICATE_PWD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
|
||||
# MACOS_KEYCHAIN_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
|
||||
# run: |
|
||||
# echo $MACOS_CERTIFICATE | base64 --decode > certificate.p12
|
||||
# security create-keychain -p "$MACOS_KEYCHAIN_PASSWORD" meshtastic.keychain
|
||||
# security default-keychain -s meshtastic.keychain
|
||||
# security unlock-keychain -p "$MACOS_KEYCHAIN_PASSWORD" meshtastic.keychain
|
||||
# security import certificate.p12 -k meshtastic.keychain -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
|
||||
# security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_KEYCHAIN_PASSWORD" meshtastic.keychain
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
MACOS_SIGNING_IDENTITY: ${{ secrets.MACOS_SIGNING_IDENTITY }}
|
||||
run: |
|
||||
pip install pyinstaller
|
||||
pip install -r requirements.txt
|
||||
pip install .
|
||||
pyinstaller -F -n meshtastic --collect-all meshtastic --codesign-identity "$MACOS_SIGNING_IDENTITY" meshtastic/__main__.py
|
||||
# - name: Build
|
||||
# env:
|
||||
# MACOS_SIGNING_IDENTITY: ${{ secrets.MACOS_SIGNING_IDENTITY }}
|
||||
# run: |
|
||||
# pip install pyinstaller
|
||||
# pip install -r requirements.txt
|
||||
# pip install .
|
||||
# pyinstaller -F -n meshtastic --collect-all meshtastic --codesign-identity "$MACOS_SIGNING_IDENTITY" meshtastic/__main__.py
|
||||
|
||||
- name: Add mac to release
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.release_create.outputs.upload_url }}
|
||||
asset_path: dist/meshtastic
|
||||
asset_name: meshtastic_mac
|
||||
asset_content_type: application/zip
|
||||
# - name: Add mac to release
|
||||
# uses: actions/upload-release-asset@v1
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# with:
|
||||
# upload_url: ${{ needs.release_create.outputs.upload_url }}
|
||||
# asset_path: dist/meshtastic
|
||||
# asset_name: meshtastic_mac
|
||||
# asset_content_type: application/zip
|
||||
|
||||
build-and-publish-ubuntu:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
10
.vscode/launch.json
vendored
10
.vscode/launch.json
vendored
@@ -10,7 +10,7 @@
|
||||
"request": "launch",
|
||||
"module": "meshtastic",
|
||||
"justMyCode": false,
|
||||
"args": ["--debug", "--ble", "--device", "24:62:AB:DD:DF:3A"]
|
||||
"args": ["--debug", "--ble", "24:62:AB:DD:DF:3A"]
|
||||
},
|
||||
{
|
||||
"name": "meshtastic admin",
|
||||
@@ -44,6 +44,14 @@
|
||||
"justMyCode": true,
|
||||
"args": ["--debug"]
|
||||
},
|
||||
{
|
||||
"name": "meshtastic listen",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"module": "meshtastic",
|
||||
"justMyCode": true,
|
||||
"args": ["--listen", "--debug"]
|
||||
},
|
||||
{
|
||||
"name": "meshtastic debug getPref",
|
||||
"type": "python",
|
||||
|
||||
8
TODO.md
8
TODO.md
@@ -5,7 +5,6 @@ Basic functionality is complete now.
|
||||
## Eventual tasks
|
||||
|
||||
- Improve documentation on properties/fields
|
||||
- change back to Bleak for BLE support - now that they fixed https://github.com/hbldh/bleak/issues/139#event-3499535304
|
||||
- include more examples: textchat.py, replymessage.py all as one little demo
|
||||
|
||||
- possibly use tk to make a multiwindow test console: https://stackoverflow.com/questions/12351786/how-to-redirect-print-statements-to-tkinter-text-widget
|
||||
@@ -17,11 +16,8 @@ Basic functionality is complete now.
|
||||
|
||||
## Bluetooth support
|
||||
|
||||
(Pre-alpha level feature - you probably don't want this one yet)
|
||||
|
||||
- This library supports connecting to Meshtastic devices over either USB (serial) or Bluetooth. Before connecting to the device you must [pair](https://docs.ubuntu.com/core/en/stacks/bluetooth/bluez/docs/reference/pairing/outbound.html) your PC with it.
|
||||
- We use the pip3 install "pygatt[GATTTOOL]"
|
||||
- ./bin/run.sh --debug --ble --device 24:62:AB:DD:DF:3A
|
||||
- ./bin/run.sh --ble-scan # To look for Meshtastic devices
|
||||
- ./bin/run.sh --ble 24:62:AB:DD:DF:3A --info
|
||||
|
||||
## Done
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import platform
|
||||
import sys
|
||||
import time
|
||||
|
||||
import pkg_resources
|
||||
import pyqrcode
|
||||
import yaml
|
||||
from google.protobuf.json_format import MessageToDict
|
||||
@@ -18,6 +17,7 @@ from pubsub import pub
|
||||
import meshtastic.test
|
||||
import meshtastic.util
|
||||
from meshtastic import channel_pb2, config_pb2, portnums_pb2, remote_hardware
|
||||
from meshtastic.version import get_active_version
|
||||
from meshtastic.__init__ import BROADCAST_ADDR
|
||||
from meshtastic.ble_interface import BLEInterface
|
||||
from meshtastic.globals import Globals
|
||||
@@ -135,7 +135,7 @@ def splitCompoundName(comp_name):
|
||||
return name
|
||||
|
||||
|
||||
def setPref(config, comp_name, valStr):
|
||||
def setPref(config, comp_name, valStr) -> bool:
|
||||
"""Set a channel or preferences value"""
|
||||
|
||||
name = splitCompoundName(comp_name)
|
||||
@@ -597,6 +597,12 @@ def onConnected(interface):
|
||||
# handle changing channels
|
||||
|
||||
if args.ch_add:
|
||||
channelIndex = our_globals.get_channel_index()
|
||||
if channelIndex is not None:
|
||||
# Since we set the channel index after adding a channel, don't allow --ch-index
|
||||
meshtastic.util.our_exit(
|
||||
"Warning: '--ch-add' and '--ch-index' are incompatible. Channel not added."
|
||||
)
|
||||
closeNow = True
|
||||
if len(args.ch_add) > 10:
|
||||
meshtastic.util.our_exit(
|
||||
@@ -620,6 +626,9 @@ def onConnected(interface):
|
||||
ch.role = channel_pb2.Channel.Role.SECONDARY
|
||||
print(f"Writing modified channels to device")
|
||||
n.writeChannel(ch.index)
|
||||
if channelIndex is None:
|
||||
print(f"Setting newly-added channel's {ch.index} as '--ch-index' for further modifications")
|
||||
our_globals.set_channel_index(ch.index)
|
||||
|
||||
if args.ch_del:
|
||||
closeNow = True
|
||||
@@ -690,9 +699,29 @@ def onConnected(interface):
|
||||
# Handle the channel settings
|
||||
for pref in args.ch_set or []:
|
||||
if pref[0] == "psk":
|
||||
found = True
|
||||
ch.settings.psk = meshtastic.util.fromPSK(pref[1])
|
||||
else:
|
||||
setPref(ch.settings, pref[0], pref[1])
|
||||
found = setPref(ch.settings, pref[0], pref[1])
|
||||
if not found:
|
||||
category_settings = ['module_settings']
|
||||
print(
|
||||
f"{ch.settings.__class__.__name__} does not have an attribute {pref[0]}."
|
||||
)
|
||||
print("Choices are...")
|
||||
for field in ch.settings.DESCRIPTOR.fields:
|
||||
if field.name not in category_settings:
|
||||
print(f"{field.name}")
|
||||
else:
|
||||
print(f"{field.name}:")
|
||||
config = ch.settings.DESCRIPTOR.fields_by_name.get(field.name)
|
||||
names = []
|
||||
for sub_field in config.message_type.fields:
|
||||
tmp_name = f"{field.name}.{sub_field.name}"
|
||||
names.append(tmp_name)
|
||||
for temp_name in sorted(names):
|
||||
print(f" {temp_name}")
|
||||
|
||||
enable = True # If we set any pref, assume the user wants to enable the channel
|
||||
|
||||
if enable:
|
||||
@@ -761,6 +790,9 @@ def onConnected(interface):
|
||||
qr = pyqrcode.create(url)
|
||||
print(qr.terminal())
|
||||
|
||||
if args.listen:
|
||||
closeNow = False
|
||||
|
||||
have_tunnel = platform.system() == "Linux"
|
||||
if have_tunnel and args.tunnel:
|
||||
# pylint: disable=C0415
|
||||
@@ -945,7 +977,17 @@ def common():
|
||||
our_globals.set_logfile(logfile)
|
||||
|
||||
subscribe()
|
||||
if args.ble:
|
||||
if args.ble_scan:
|
||||
logging.debug("BLE scan starting")
|
||||
client = BLEInterface(None, debugOut=logfile, noProto=args.noproto)
|
||||
try:
|
||||
for x in client.scan():
|
||||
print(f"Found: name='{x[1].local_name}' address='{x[0].address}'")
|
||||
finally:
|
||||
client.close()
|
||||
meshtastic.util.our_exit("BLE scan finished", 0)
|
||||
return
|
||||
elif args.ble:
|
||||
client = BLEInterface(args.ble, debugOut=logfile, noProto=args.noproto)
|
||||
elif args.host:
|
||||
try:
|
||||
@@ -971,13 +1013,23 @@ 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)
|
||||
if client.devPath is None:
|
||||
try:
|
||||
client = meshtastic.tcp_interface.TCPInterface(
|
||||
"localhost", debugOut=logfile, noProto=args.noproto
|
||||
)
|
||||
except Exception as ex:
|
||||
meshtastic.util.our_exit(
|
||||
f"Error connecting to localhost:{ex}", 1
|
||||
)
|
||||
|
||||
|
||||
# We assume client is fully connected now
|
||||
onConnected(client)
|
||||
|
||||
have_tunnel = platform.system() == "Linux"
|
||||
if (
|
||||
args.noproto or args.reply or (have_tunnel and args.tunnel)
|
||||
args.noproto or args.reply or (have_tunnel and args.tunnel) or args.listen
|
||||
): # loop until someone presses ctrlc
|
||||
while True:
|
||||
time.sleep(1000)
|
||||
@@ -1006,7 +1058,7 @@ def initParser():
|
||||
|
||||
parser.add_argument(
|
||||
"--port",
|
||||
help="The port the Meshtastic device is connected to, i.e. /dev/ttyUSB0. If unspecified, we'll try to find it.",
|
||||
help="The port the Meshtastic device is connected to, i.e. /dev/ttyUSB0.",
|
||||
default=None,
|
||||
)
|
||||
|
||||
@@ -1208,7 +1260,7 @@ def initParser():
|
||||
help="Request telemetry from a node. "
|
||||
"You need pass the destination ID as argument with '--dest'. "
|
||||
"For repeaters, the nodeNum is required.",
|
||||
action="store_true",
|
||||
action="store_true",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
@@ -1310,9 +1362,14 @@ def initParser():
|
||||
|
||||
parser.add_argument(
|
||||
"--ble",
|
||||
help="BLE mac address to connect to (BLE is not yet supported for this tool)",
|
||||
help="BLE device address or name to connect to",
|
||||
default=None,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--ble-scan",
|
||||
help="Scan for Meshtastic BLE devices",
|
||||
action="store_true",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--noproto",
|
||||
@@ -1320,6 +1377,12 @@ def initParser():
|
||||
action="store_true",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--listen",
|
||||
help="Just stay open and listen to the protobuf stream.",
|
||||
action="store_true",
|
||||
)
|
||||
|
||||
have_tunnel = platform.system() == "Linux"
|
||||
if have_tunnel:
|
||||
parser.add_argument(
|
||||
@@ -1336,7 +1399,7 @@ def initParser():
|
||||
|
||||
parser.set_defaults(deprecated=None)
|
||||
|
||||
the_version = pkg_resources.get_distribution("meshtastic").version
|
||||
the_version = get_active_version()
|
||||
parser.add_argument("--version", action="version", version=f"{the_version}")
|
||||
|
||||
parser.add_argument(
|
||||
@@ -1353,7 +1416,9 @@ def initParser():
|
||||
def main():
|
||||
"""Perform command line meshtastic operations"""
|
||||
our_globals = Globals.getInstance()
|
||||
parser = argparse.ArgumentParser()
|
||||
parser = argparse.ArgumentParser(
|
||||
epilog="If neither --port nor --host are specified, we search for a compatible serial device, "
|
||||
"and if none is found, then attempt a TCP connection to localhost.")
|
||||
our_globals.set_parser(parser)
|
||||
initParser()
|
||||
common()
|
||||
|
||||
@@ -19,7 +19,7 @@ from meshtastic import mesh_pb2 as meshtastic_dot_mesh__pb2
|
||||
from meshtastic import module_config_pb2 as meshtastic_dot_module__config__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16meshtastic/admin.proto\x1a\x18meshtastic/channel.proto\x1a\x17meshtastic/config.proto\x1a\"meshtastic/connection_status.proto\x1a\x1bmeshtastic/deviceonly.proto\x1a\x15meshtastic/mesh.proto\x1a\x1emeshtastic/module_config.proto\"\x83\x0f\n\x0c\x41\x64minMessage\x12\x1d\n\x13get_channel_request\x18\x01 \x01(\rH\x00\x12(\n\x14get_channel_response\x18\x02 \x01(\x0b\x32\x08.ChannelH\x00\x12\x1b\n\x11get_owner_request\x18\x03 \x01(\x08H\x00\x12#\n\x12get_owner_response\x18\x04 \x01(\x0b\x32\x05.UserH\x00\x12\x36\n\x12get_config_request\x18\x05 \x01(\x0e\x32\x18.AdminMessage.ConfigTypeH\x00\x12&\n\x13get_config_response\x18\x06 \x01(\x0b\x32\x07.ConfigH\x00\x12\x43\n\x19get_module_config_request\x18\x07 \x01(\x0e\x32\x1e.AdminMessage.ModuleConfigTypeH\x00\x12\x33\n\x1aget_module_config_response\x18\x08 \x01(\x0b\x32\r.ModuleConfigH\x00\x12\x34\n*get_canned_message_module_messages_request\x18\n \x01(\x08H\x00\x12\x35\n+get_canned_message_module_messages_response\x18\x0b \x01(\tH\x00\x12%\n\x1bget_device_metadata_request\x18\x0c \x01(\x08H\x00\x12\x37\n\x1cget_device_metadata_response\x18\r \x01(\x0b\x32\x0f.DeviceMetadataH\x00\x12\x1e\n\x14get_ringtone_request\x18\x0e \x01(\x08H\x00\x12\x1f\n\x15get_ringtone_response\x18\x0f \x01(\tH\x00\x12.\n$get_device_connection_status_request\x18\x10 \x01(\x08H\x00\x12H\n%get_device_connection_status_response\x18\x11 \x01(\x0b\x32\x17.DeviceConnectionStatusH\x00\x12&\n\x0cset_ham_mode\x18\x12 \x01(\x0b\x32\x0e.HamParametersH\x00\x12/\n%get_node_remote_hardware_pins_request\x18\x13 \x01(\x08H\x00\x12Q\n&get_node_remote_hardware_pins_response\x18\x14 \x01(\x0b\x32\x1f.NodeRemoteHardwarePinsResponseH\x00\x12 \n\x16\x65nter_dfu_mode_request\x18\x15 \x01(\x08H\x00\x12\x1a\n\tset_owner\x18 \x01(\x0b\x32\x05.UserH\x00\x12\x1f\n\x0bset_channel\x18! \x01(\x0b\x32\x08.ChannelH\x00\x12\x1d\n\nset_config\x18\" \x01(\x0b\x32\x07.ConfigH\x00\x12*\n\x11set_module_config\x18# \x01(\x0b\x32\r.ModuleConfigH\x00\x12,\n\"set_canned_message_module_messages\x18$ \x01(\tH\x00\x12\x1e\n\x14set_ringtone_message\x18% \x01(\tH\x00\x12\x1b\n\x11remove_by_nodenum\x18& \x01(\rH\x00\x12\x1d\n\x13\x62\x65gin_edit_settings\x18@ \x01(\x08H\x00\x12\x1e\n\x14\x63ommit_edit_settings\x18\x41 \x01(\x08H\x00\x12\x1c\n\x12reboot_ota_seconds\x18_ \x01(\x05H\x00\x12\x18\n\x0e\x65xit_simulator\x18` \x01(\x08H\x00\x12\x18\n\x0ereboot_seconds\x18\x61 \x01(\x05H\x00\x12\x1a\n\x10shutdown_seconds\x18\x62 \x01(\x05H\x00\x12\x17\n\rfactory_reset\x18\x63 \x01(\x05H\x00\x12\x16\n\x0cnodedb_reset\x18\x64 \x01(\x05H\x00\"\x95\x01\n\nConfigType\x12\x11\n\rDEVICE_CONFIG\x10\x00\x12\x13\n\x0fPOSITION_CONFIG\x10\x01\x12\x10\n\x0cPOWER_CONFIG\x10\x02\x12\x12\n\x0eNETWORK_CONFIG\x10\x03\x12\x12\n\x0e\x44ISPLAY_CONFIG\x10\x04\x12\x0f\n\x0bLORA_CONFIG\x10\x05\x12\x14\n\x10\x42LUETOOTH_CONFIG\x10\x06\"\xbb\x02\n\x10ModuleConfigType\x12\x0f\n\x0bMQTT_CONFIG\x10\x00\x12\x11\n\rSERIAL_CONFIG\x10\x01\x12\x13\n\x0f\x45XTNOTIF_CONFIG\x10\x02\x12\x17\n\x13STOREFORWARD_CONFIG\x10\x03\x12\x14\n\x10RANGETEST_CONFIG\x10\x04\x12\x14\n\x10TELEMETRY_CONFIG\x10\x05\x12\x14\n\x10\x43\x41NNEDMSG_CONFIG\x10\x06\x12\x10\n\x0c\x41UDIO_CONFIG\x10\x07\x12\x19\n\x15REMOTEHARDWARE_CONFIG\x10\x08\x12\x17\n\x13NEIGHBORINFO_CONFIG\x10\t\x12\x1a\n\x16\x41MBIENTLIGHTING_CONFIG\x10\n\x12\x1a\n\x16\x44\x45TECTIONSENSOR_CONFIG\x10\x0b\x12\x15\n\x11PAXCOUNTER_CONFIG\x10\x0c\x42\x11\n\x0fpayload_variant\"[\n\rHamParameters\x12\x11\n\tcall_sign\x18\x01 \x01(\t\x12\x10\n\x08tx_power\x18\x02 \x01(\x05\x12\x11\n\tfrequency\x18\x03 \x01(\x02\x12\x12\n\nshort_name\x18\x04 \x01(\t\"[\n\x1eNodeRemoteHardwarePinsResponse\x12\x39\n\x19node_remote_hardware_pins\x18\x01 \x03(\x0b\x32\x16.NodeRemoteHardwarePinB`\n\x13\x63om.geeksville.meshB\x0b\x41\x64minProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x16meshtastic/admin.proto\x1a\x18meshtastic/channel.proto\x1a\x17meshtastic/config.proto\x1a\"meshtastic/connection_status.proto\x1a\x1bmeshtastic/deviceonly.proto\x1a\x15meshtastic/mesh.proto\x1a\x1emeshtastic/module_config.proto\"\xa2\x0f\n\x0c\x41\x64minMessage\x12\x1d\n\x13get_channel_request\x18\x01 \x01(\rH\x00\x12(\n\x14get_channel_response\x18\x02 \x01(\x0b\x32\x08.ChannelH\x00\x12\x1b\n\x11get_owner_request\x18\x03 \x01(\x08H\x00\x12#\n\x12get_owner_response\x18\x04 \x01(\x0b\x32\x05.UserH\x00\x12\x36\n\x12get_config_request\x18\x05 \x01(\x0e\x32\x18.AdminMessage.ConfigTypeH\x00\x12&\n\x13get_config_response\x18\x06 \x01(\x0b\x32\x07.ConfigH\x00\x12\x43\n\x19get_module_config_request\x18\x07 \x01(\x0e\x32\x1e.AdminMessage.ModuleConfigTypeH\x00\x12\x33\n\x1aget_module_config_response\x18\x08 \x01(\x0b\x32\r.ModuleConfigH\x00\x12\x34\n*get_canned_message_module_messages_request\x18\n \x01(\x08H\x00\x12\x35\n+get_canned_message_module_messages_response\x18\x0b \x01(\tH\x00\x12%\n\x1bget_device_metadata_request\x18\x0c \x01(\x08H\x00\x12\x37\n\x1cget_device_metadata_response\x18\r \x01(\x0b\x32\x0f.DeviceMetadataH\x00\x12\x1e\n\x14get_ringtone_request\x18\x0e \x01(\x08H\x00\x12\x1f\n\x15get_ringtone_response\x18\x0f \x01(\tH\x00\x12.\n$get_device_connection_status_request\x18\x10 \x01(\x08H\x00\x12H\n%get_device_connection_status_response\x18\x11 \x01(\x0b\x32\x17.DeviceConnectionStatusH\x00\x12&\n\x0cset_ham_mode\x18\x12 \x01(\x0b\x32\x0e.HamParametersH\x00\x12/\n%get_node_remote_hardware_pins_request\x18\x13 \x01(\x08H\x00\x12Q\n&get_node_remote_hardware_pins_response\x18\x14 \x01(\x0b\x32\x1f.NodeRemoteHardwarePinsResponseH\x00\x12 \n\x16\x65nter_dfu_mode_request\x18\x15 \x01(\x08H\x00\x12\x1d\n\x13\x64\x65lete_file_request\x18\x16 \x01(\tH\x00\x12\x1a\n\tset_owner\x18 \x01(\x0b\x32\x05.UserH\x00\x12\x1f\n\x0bset_channel\x18! \x01(\x0b\x32\x08.ChannelH\x00\x12\x1d\n\nset_config\x18\" \x01(\x0b\x32\x07.ConfigH\x00\x12*\n\x11set_module_config\x18# \x01(\x0b\x32\r.ModuleConfigH\x00\x12,\n\"set_canned_message_module_messages\x18$ \x01(\tH\x00\x12\x1e\n\x14set_ringtone_message\x18% \x01(\tH\x00\x12\x1b\n\x11remove_by_nodenum\x18& \x01(\rH\x00\x12\x1d\n\x13\x62\x65gin_edit_settings\x18@ \x01(\x08H\x00\x12\x1e\n\x14\x63ommit_edit_settings\x18\x41 \x01(\x08H\x00\x12\x1c\n\x12reboot_ota_seconds\x18_ \x01(\x05H\x00\x12\x18\n\x0e\x65xit_simulator\x18` \x01(\x08H\x00\x12\x18\n\x0ereboot_seconds\x18\x61 \x01(\x05H\x00\x12\x1a\n\x10shutdown_seconds\x18\x62 \x01(\x05H\x00\x12\x17\n\rfactory_reset\x18\x63 \x01(\x05H\x00\x12\x16\n\x0cnodedb_reset\x18\x64 \x01(\x05H\x00\"\x95\x01\n\nConfigType\x12\x11\n\rDEVICE_CONFIG\x10\x00\x12\x13\n\x0fPOSITION_CONFIG\x10\x01\x12\x10\n\x0cPOWER_CONFIG\x10\x02\x12\x12\n\x0eNETWORK_CONFIG\x10\x03\x12\x12\n\x0e\x44ISPLAY_CONFIG\x10\x04\x12\x0f\n\x0bLORA_CONFIG\x10\x05\x12\x14\n\x10\x42LUETOOTH_CONFIG\x10\x06\"\xbb\x02\n\x10ModuleConfigType\x12\x0f\n\x0bMQTT_CONFIG\x10\x00\x12\x11\n\rSERIAL_CONFIG\x10\x01\x12\x13\n\x0f\x45XTNOTIF_CONFIG\x10\x02\x12\x17\n\x13STOREFORWARD_CONFIG\x10\x03\x12\x14\n\x10RANGETEST_CONFIG\x10\x04\x12\x14\n\x10TELEMETRY_CONFIG\x10\x05\x12\x14\n\x10\x43\x41NNEDMSG_CONFIG\x10\x06\x12\x10\n\x0c\x41UDIO_CONFIG\x10\x07\x12\x19\n\x15REMOTEHARDWARE_CONFIG\x10\x08\x12\x17\n\x13NEIGHBORINFO_CONFIG\x10\t\x12\x1a\n\x16\x41MBIENTLIGHTING_CONFIG\x10\n\x12\x1a\n\x16\x44\x45TECTIONSENSOR_CONFIG\x10\x0b\x12\x15\n\x11PAXCOUNTER_CONFIG\x10\x0c\x42\x11\n\x0fpayload_variant\"[\n\rHamParameters\x12\x11\n\tcall_sign\x18\x01 \x01(\t\x12\x10\n\x08tx_power\x18\x02 \x01(\x05\x12\x11\n\tfrequency\x18\x03 \x01(\x02\x12\x12\n\nshort_name\x18\x04 \x01(\t\"[\n\x1eNodeRemoteHardwarePinsResponse\x12\x39\n\x19node_remote_hardware_pins\x18\x01 \x03(\x0b\x32\x16.NodeRemoteHardwarePinB`\n\x13\x63om.geeksville.meshB\x0b\x41\x64minProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.admin_pb2', globals())
|
||||
@@ -28,13 +28,13 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\013AdminProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
|
||||
_ADMINMESSAGE._serialized_start=198
|
||||
_ADMINMESSAGE._serialized_end=2121
|
||||
_ADMINMESSAGE_CONFIGTYPE._serialized_start=1635
|
||||
_ADMINMESSAGE_CONFIGTYPE._serialized_end=1784
|
||||
_ADMINMESSAGE_MODULECONFIGTYPE._serialized_start=1787
|
||||
_ADMINMESSAGE_MODULECONFIGTYPE._serialized_end=2102
|
||||
_HAMPARAMETERS._serialized_start=2123
|
||||
_HAMPARAMETERS._serialized_end=2214
|
||||
_NODEREMOTEHARDWAREPINSRESPONSE._serialized_start=2216
|
||||
_NODEREMOTEHARDWAREPINSRESPONSE._serialized_end=2307
|
||||
_ADMINMESSAGE._serialized_end=2152
|
||||
_ADMINMESSAGE_CONFIGTYPE._serialized_start=1666
|
||||
_ADMINMESSAGE_CONFIGTYPE._serialized_end=1815
|
||||
_ADMINMESSAGE_MODULECONFIGTYPE._serialized_start=1818
|
||||
_ADMINMESSAGE_MODULECONFIGTYPE._serialized_end=2133
|
||||
_HAMPARAMETERS._serialized_start=2154
|
||||
_HAMPARAMETERS._serialized_end=2245
|
||||
_NODEREMOTEHARDWAREPINSRESPONSE._serialized_start=2247
|
||||
_NODEREMOTEHARDWAREPINSRESPONSE._serialized_end=2338
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
||||
40
meshtastic/atak_pb2.py
Normal file
40
meshtastic/atak_pb2.py
Normal file
@@ -0,0 +1,40 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: meshtastic/atak.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf.internal import builder as _builder
|
||||
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
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15meshtastic/atak.proto\"\xaf\x01\n\tTAKPacket\x12\x15\n\ris_compressed\x18\x01 \x01(\x08\x12\x19\n\x07\x63ontact\x18\x02 \x01(\x0b\x32\x08.Contact\x12\x15\n\x05group\x18\x03 \x01(\x0b\x32\x06.Group\x12\x17\n\x06status\x18\x04 \x01(\x0b\x32\x07.Status\x12\x13\n\x03pli\x18\x05 \x01(\x0b\x32\x04.PLIH\x00\x12\x18\n\x04\x63hat\x18\x06 \x01(\x0b\x32\x08.GeoChatH\x00\x42\x11\n\x0fpayload_variant\"2\n\x07GeoChat\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x0f\n\x02to\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x05\n\x03_to\"7\n\x05Group\x12\x19\n\x04role\x18\x01 \x01(\x0e\x32\x0b.MemberRole\x12\x13\n\x04team\x18\x02 \x01(\x0e\x32\x05.Team\"\x19\n\x06Status\x12\x0f\n\x07\x62\x61ttery\x18\x01 \x01(\r\"4\n\x07\x43ontact\x12\x10\n\x08\x63\x61llsign\x18\x01 \x01(\t\x12\x17\n\x0f\x64\x65vice_callsign\x18\x02 \x01(\t\"_\n\x03PLI\x12\x12\n\nlatitude_i\x18\x01 \x01(\x0f\x12\x13\n\x0blongitude_i\x18\x02 \x01(\x0f\x12\x10\n\x08\x61ltitude\x18\x03 \x01(\x05\x12\r\n\x05speed\x18\x04 \x01(\r\x12\x0e\n\x06\x63ourse\x18\x05 \x01(\r*\xc0\x01\n\x04Team\x12\x14\n\x10Unspecifed_Color\x10\x00\x12\t\n\x05White\x10\x01\x12\n\n\x06Yellow\x10\x02\x12\n\n\x06Orange\x10\x03\x12\x0b\n\x07Magenta\x10\x04\x12\x07\n\x03Red\x10\x05\x12\n\n\x06Maroon\x10\x06\x12\n\n\x06Purple\x10\x07\x12\r\n\tDark_Blue\x10\x08\x12\x08\n\x04\x42lue\x10\t\x12\x08\n\x04\x43yan\x10\n\x12\x08\n\x04Teal\x10\x0b\x12\t\n\x05Green\x10\x0c\x12\x0e\n\nDark_Green\x10\r\x12\t\n\x05\x42rown\x10\x0e*\x7f\n\nMemberRole\x12\x0e\n\nUnspecifed\x10\x00\x12\x0e\n\nTeamMember\x10\x01\x12\x0c\n\x08TeamLead\x10\x02\x12\x06\n\x02HQ\x10\x03\x12\n\n\x06Sniper\x10\x04\x12\t\n\x05Medic\x10\x05\x12\x13\n\x0f\x46orwardObserver\x10\x06\x12\x07\n\x03RTO\x10\x07\x12\x06\n\x02K9\x10\x08\x42_\n\x13\x63om.geeksville.meshB\nATAKProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.atak_pb2', globals())
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\nATAKProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
|
||||
_TEAM._serialized_start=491
|
||||
_TEAM._serialized_end=683
|
||||
_MEMBERROLE._serialized_start=685
|
||||
_MEMBERROLE._serialized_end=812
|
||||
_TAKPACKET._serialized_start=26
|
||||
_TAKPACKET._serialized_end=201
|
||||
_GEOCHAT._serialized_start=203
|
||||
_GEOCHAT._serialized_end=253
|
||||
_GROUP._serialized_start=255
|
||||
_GROUP._serialized_end=310
|
||||
_STATUS._serialized_start=312
|
||||
_STATUS._serialized_end=337
|
||||
_CONTACT._serialized_start=339
|
||||
_CONTACT._serialized_end=391
|
||||
_PLI._serialized_start=393
|
||||
_PLI._serialized_end=488
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -1,66 +1,236 @@
|
||||
"""Bluetooth interface
|
||||
"""
|
||||
import logging
|
||||
import platform
|
||||
import time
|
||||
import struct
|
||||
import asyncio
|
||||
from threading import Thread, Event
|
||||
from bleak import BleakScanner, BleakClient
|
||||
|
||||
from meshtastic.mesh_interface import MeshInterface
|
||||
from meshtastic.util import our_exit
|
||||
|
||||
if platform.system() == "Linux":
|
||||
# pylint: disable=E0401
|
||||
import pygatt
|
||||
|
||||
|
||||
# Our standard BLE characteristics
|
||||
SERVICE_UUID = "6ba1b218-15a8-461f-9fa8-5dcae273eafd"
|
||||
TORADIO_UUID = "f75c76d2-129e-4dad-a1dd-7866124401e7"
|
||||
FROMRADIO_UUID = "8ba2bcc2-ee02-4a55-a531-c525c5e454d5"
|
||||
FROMRADIO_UUID = "2c55e69e-4993-11ed-b878-0242ac120002"
|
||||
FROMNUM_UUID = "ed9da18c-a800-4f66-a670-aa7547e34453"
|
||||
|
||||
|
||||
class BLEInterface(MeshInterface):
|
||||
"""A not quite ready - FIXME - BLE interface to devices"""
|
||||
"""MeshInterface using BLE to connect to devices"""
|
||||
class BLEError(Exception):
|
||||
"""An exception class for BLE errors"""
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
super().__init__(self.message)
|
||||
|
||||
def __init__(self, address, noProto=False, debugOut=None):
|
||||
if platform.system() != "Linux":
|
||||
our_exit("Linux is the only platform with experimental BLE support.", 1)
|
||||
self.address = address
|
||||
if not noProto:
|
||||
self.adapter = pygatt.GATTToolBackend() # BGAPIBackend()
|
||||
self.adapter.start()
|
||||
logging.debug(f"Connecting to {self.address}")
|
||||
self.device = self.adapter.connect(address)
|
||||
else:
|
||||
self.adapter = None
|
||||
self.device = None
|
||||
logging.debug("Connected to device")
|
||||
# fromradio = self.device.char_read(FROMRADIO_UUID)
|
||||
MeshInterface.__init__(self, debugOut=debugOut, noProto=noProto)
|
||||
class BLEState(): # pylint: disable=C0115
|
||||
THREADS = False
|
||||
BLE = False
|
||||
MESH = False
|
||||
|
||||
self._readFromRadio() # read the initial responses
|
||||
|
||||
def handle_data(handle, data): # pylint: disable=W0613
|
||||
self._handleFromRadio(data)
|
||||
def __init__(self, address, noProto = False, debugOut = None):
|
||||
self.state = BLEInterface.BLEState()
|
||||
|
||||
if self.device:
|
||||
self.device.subscribe(FROMNUM_UUID, callback=handle_data)
|
||||
if not address:
|
||||
return
|
||||
|
||||
self.should_read = False
|
||||
|
||||
logging.debug("Threads starting")
|
||||
self._receiveThread = Thread(target = self._receiveFromRadioImpl)
|
||||
self._receiveThread_started = Event()
|
||||
self._receiveThread_stopped = Event()
|
||||
self._receiveThread.start()
|
||||
self._receiveThread_started.wait(1)
|
||||
self.state.THREADS = True
|
||||
logging.debug("Threads running")
|
||||
|
||||
try:
|
||||
logging.debug(f"BLE connecting to: {address}")
|
||||
self.client = self.connect(address)
|
||||
self.state.BLE = True
|
||||
logging.debug("BLE connected")
|
||||
except BLEInterface.BLEError as e:
|
||||
self.close()
|
||||
our_exit(e.message, 1)
|
||||
return
|
||||
|
||||
logging.debug("Mesh init starting")
|
||||
MeshInterface.__init__(self, debugOut = debugOut, noProto = noProto)
|
||||
self._startConfig()
|
||||
if not self.noProto:
|
||||
self._waitConnected(timeout = 60.0)
|
||||
self.waitForConfig()
|
||||
self.state.MESH = True
|
||||
logging.debug("Mesh init finished")
|
||||
|
||||
logging.debug("Register FROMNUM notify callback")
|
||||
self.client.start_notify(FROMNUM_UUID, self.from_num_handler)
|
||||
|
||||
|
||||
async def from_num_handler(self, _, b): # pylint: disable=C0116
|
||||
from_num = struct.unpack('<I', bytes(b))[0]
|
||||
logging.debug(f"FROMNUM notify: {from_num}")
|
||||
self.should_read = True
|
||||
|
||||
|
||||
def scan(self):
|
||||
"Scan for available BLE devices"
|
||||
with BLEClient() as client:
|
||||
return [
|
||||
(x[0], x[1]) for x in (client.discover(
|
||||
return_adv = True,
|
||||
service_uuids = [ SERVICE_UUID ]
|
||||
)).values()
|
||||
]
|
||||
|
||||
|
||||
def find_device(self, address):
|
||||
"Find a device by address"
|
||||
meshtastic_devices = self.scan()
|
||||
|
||||
addressed_devices = list(filter(lambda x: address in (x[1].local_name, x[0].name), meshtastic_devices))
|
||||
# If nothing is found try on the address
|
||||
if len(addressed_devices) == 0:
|
||||
addressed_devices = list(filter(
|
||||
lambda x: BLEInterface._sanitize_address(address) == BLEInterface._sanitize_address(x[0].address),
|
||||
meshtastic_devices))
|
||||
|
||||
if len(addressed_devices) == 0:
|
||||
raise BLEInterface.BLEError(f"No Meshtastic BLE peripheral with identifier or address '{address}' found. Try --ble-scan to find it.")
|
||||
if len(addressed_devices) > 1:
|
||||
raise BLEInterface.BLEError(f"More than one Meshtastic BLE peripheral with identifier or address '{address}' found.")
|
||||
return addressed_devices[0][0]
|
||||
|
||||
def _sanitize_address(address): # pylint: disable=E0213
|
||||
"Standardize BLE address by removing extraneous characters and lowercasing"
|
||||
return address \
|
||||
.replace("-", "") \
|
||||
.replace("_", "") \
|
||||
.replace(":", "") \
|
||||
.lower()
|
||||
|
||||
def connect(self, address):
|
||||
"Connect to a device by address"
|
||||
device = self.find_device(address)
|
||||
client = BLEClient(device.address)
|
||||
client.connect()
|
||||
try:
|
||||
client.pair()
|
||||
except NotImplementedError:
|
||||
# Some bluetooth backends do not require explicit pairing.
|
||||
# See Bleak docs for details on this.
|
||||
pass
|
||||
return client
|
||||
|
||||
|
||||
def _receiveFromRadioImpl(self):
|
||||
self._receiveThread_started.set()
|
||||
while self._receiveThread_started.is_set():
|
||||
if self.should_read:
|
||||
self.should_read = False
|
||||
retries = 0
|
||||
while True:
|
||||
b = bytes(self.client.read_gatt_char(FROMRADIO_UUID))
|
||||
if not b:
|
||||
if retries < 5:
|
||||
time.sleep(0.1)
|
||||
retries += 1
|
||||
continue
|
||||
break
|
||||
logging.debug(f"FROMRADIO read: {b.hex()}")
|
||||
self._handleFromRadio(b)
|
||||
else:
|
||||
time.sleep(0.1)
|
||||
self._receiveThread_stopped.set()
|
||||
|
||||
def _sendToRadioImpl(self, toRadio):
|
||||
"""Send a ToRadio protobuf to the device"""
|
||||
# logging.debug(f"Sending: {stripnl(toRadio)}")
|
||||
b = toRadio.SerializeToString()
|
||||
self.device.char_write(TORADIO_UUID, b)
|
||||
if b:
|
||||
logging.debug(f"TORADIO write: {b.hex()}")
|
||||
self.client.write_gatt_char(TORADIO_UUID, b, response = True)
|
||||
# Allow to propagate and then make sure we read
|
||||
time.sleep(0.1)
|
||||
self.should_read = True
|
||||
|
||||
|
||||
def close(self):
|
||||
MeshInterface.close(self)
|
||||
if self.adapter:
|
||||
self.adapter.stop()
|
||||
if self.state.MESH:
|
||||
MeshInterface.close(self)
|
||||
|
||||
def _readFromRadio(self):
|
||||
if not self.noProto:
|
||||
wasEmpty = False
|
||||
while not wasEmpty:
|
||||
if self.device:
|
||||
b = self.device.char_read(FROMRADIO_UUID)
|
||||
wasEmpty = len(b) == 0
|
||||
if not wasEmpty:
|
||||
self._handleFromRadio(b)
|
||||
if self.state.THREADS:
|
||||
self._receiveThread_started.clear()
|
||||
self._receiveThread_stopped.wait(5)
|
||||
|
||||
if self.state.BLE:
|
||||
self.client.disconnect()
|
||||
self.client.close()
|
||||
|
||||
|
||||
class BLEClient():
|
||||
"""Client for managing connection to a BLE device"""
|
||||
def __init__(self, address = None, **kwargs):
|
||||
self._eventThread = Thread(target = self._run_event_loop)
|
||||
self._eventThread_started = Event()
|
||||
self._eventThread_stopped = Event()
|
||||
self._eventThread.start()
|
||||
self._eventThread_started.wait(1)
|
||||
|
||||
if not address:
|
||||
logging.debug("No address provided - only discover method will work.")
|
||||
return
|
||||
|
||||
self.bleak_client = BleakClient(address, **kwargs)
|
||||
|
||||
|
||||
def discover(self, **kwargs): # pylint: disable=C0116
|
||||
return self.async_await(BleakScanner.discover(**kwargs))
|
||||
|
||||
def pair(self, **kwargs): # pylint: disable=C0116
|
||||
return self.async_await(self.bleak_client.pair(**kwargs))
|
||||
|
||||
def connect(self, **kwargs): # pylint: disable=C0116
|
||||
return self.async_await(self.bleak_client.connect(**kwargs))
|
||||
|
||||
def disconnect(self, **kwargs): # pylint: disable=C0116
|
||||
self.async_await(self.bleak_client.disconnect(**kwargs))
|
||||
|
||||
def read_gatt_char(self, *args, **kwargs): # pylint: disable=C0116
|
||||
return self.async_await(self.bleak_client.read_gatt_char(*args, **kwargs))
|
||||
|
||||
def write_gatt_char(self, *args, **kwargs): # pylint: disable=C0116
|
||||
self.async_await(self.bleak_client.write_gatt_char(*args, **kwargs))
|
||||
|
||||
def start_notify(self, *args, **kwargs): # pylint: disable=C0116
|
||||
self.async_await(self.bleak_client.start_notify(*args, **kwargs))
|
||||
|
||||
def close(self): # pylint: disable=C0116
|
||||
self.async_run(self._stop_event_loop())
|
||||
self._eventThread_stopped.wait(5)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, _type, _value, _traceback):
|
||||
self.close()
|
||||
|
||||
def async_await(self, coro, timeout = None): # pylint: disable=C0116
|
||||
return self.async_run(coro).result(timeout)
|
||||
|
||||
def async_run(self, coro): # pylint: disable=C0116
|
||||
return asyncio.run_coroutine_threadsafe(coro, self._eventLoop)
|
||||
|
||||
def _run_event_loop(self):
|
||||
# I don't know if the event loop can be initialized in __init__ so silencing pylint
|
||||
self._eventLoop = asyncio.new_event_loop() # pylint: disable=W0201
|
||||
self._eventThread_started.set()
|
||||
try:
|
||||
self._eventLoop.run_forever()
|
||||
finally:
|
||||
self._eventLoop.close()
|
||||
self._eventThread_stopped.set()
|
||||
|
||||
async def _stop_event_loop(self):
|
||||
self._eventLoop.stop()
|
||||
|
||||
@@ -13,7 +13,7 @@ _sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18meshtastic/channel.proto\"\x83\x01\n\x0f\x43hannelSettings\x12\x17\n\x0b\x63hannel_num\x18\x01 \x01(\rB\x02\x18\x01\x12\x0b\n\x03psk\x18\x02 \x01(\x0c\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\n\n\x02id\x18\x04 \x01(\x07\x12\x16\n\x0euplink_enabled\x18\x05 \x01(\x08\x12\x18\n\x10\x64ownlink_enabled\x18\x06 \x01(\x08\"\x8b\x01\n\x07\x43hannel\x12\r\n\x05index\x18\x01 \x01(\x05\x12\"\n\x08settings\x18\x02 \x01(\x0b\x32\x10.ChannelSettings\x12\x1b\n\x04role\x18\x03 \x01(\x0e\x32\r.Channel.Role\"0\n\x04Role\x12\x0c\n\x08\x44ISABLED\x10\x00\x12\x0b\n\x07PRIMARY\x10\x01\x12\r\n\tSECONDARY\x10\x02\x42\x62\n\x13\x63om.geeksville.meshB\rChannelProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18meshtastic/channel.proto\"\xad\x01\n\x0f\x43hannelSettings\x12\x17\n\x0b\x63hannel_num\x18\x01 \x01(\rB\x02\x18\x01\x12\x0b\n\x03psk\x18\x02 \x01(\x0c\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\n\n\x02id\x18\x04 \x01(\x07\x12\x16\n\x0euplink_enabled\x18\x05 \x01(\x08\x12\x18\n\x10\x64ownlink_enabled\x18\x06 \x01(\x08\x12(\n\x0fmodule_settings\x18\x07 \x01(\x0b\x32\x0f.ModuleSettings\",\n\x0eModuleSettings\x12\x1a\n\x12position_precision\x18\x01 \x01(\r\"\x8b\x01\n\x07\x43hannel\x12\r\n\x05index\x18\x01 \x01(\x05\x12\"\n\x08settings\x18\x02 \x01(\x0b\x32\x10.ChannelSettings\x12\x1b\n\x04role\x18\x03 \x01(\x0e\x32\r.Channel.Role\"0\n\x04Role\x12\x0c\n\x08\x44ISABLED\x10\x00\x12\x0b\n\x07PRIMARY\x10\x01\x12\r\n\tSECONDARY\x10\x02\x42\x62\n\x13\x63om.geeksville.meshB\rChannelProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.channel_pb2', globals())
|
||||
@@ -24,9 +24,11 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_CHANNELSETTINGS.fields_by_name['channel_num']._options = None
|
||||
_CHANNELSETTINGS.fields_by_name['channel_num']._serialized_options = b'\030\001'
|
||||
_CHANNELSETTINGS._serialized_start=29
|
||||
_CHANNELSETTINGS._serialized_end=160
|
||||
_CHANNEL._serialized_start=163
|
||||
_CHANNEL._serialized_end=302
|
||||
_CHANNEL_ROLE._serialized_start=254
|
||||
_CHANNEL_ROLE._serialized_end=302
|
||||
_CHANNELSETTINGS._serialized_end=202
|
||||
_MODULESETTINGS._serialized_start=204
|
||||
_MODULESETTINGS._serialized_end=248
|
||||
_CHANNEL._serialized_start=251
|
||||
_CHANNEL._serialized_end=390
|
||||
_CHANNEL_ROLE._serialized_start=342
|
||||
_CHANNEL_ROLE._serialized_end=390
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -18,7 +18,7 @@ from meshtastic import telemetry_pb2 as meshtastic_dot_telemetry__pb2
|
||||
from meshtastic import module_config_pb2 as meshtastic_dot_module__config__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1bmeshtastic/deviceonly.proto\x1a\x18meshtastic/channel.proto\x1a\x1ameshtastic/localonly.proto\x1a\x15meshtastic/mesh.proto\x1a\x1ameshtastic/telemetry.proto\x1a\x1emeshtastic/module_config.proto\"\xc6\x02\n\x0b\x44\x65viceState\x12\x1c\n\x07my_node\x18\x02 \x01(\x0b\x32\x0b.MyNodeInfo\x12\x14\n\x05owner\x18\x03 \x01(\x0b\x32\x05.User\x12\"\n\rreceive_queue\x18\x05 \x03(\x0b\x32\x0b.MeshPacket\x12\x0f\n\x07version\x18\x08 \x01(\r\x12$\n\x0frx_text_message\x18\x07 \x01(\x0b\x32\x0b.MeshPacket\x12\x0f\n\x07no_save\x18\t \x01(\x08\x12\x15\n\rdid_gps_reset\x18\x0b \x01(\x08\x12 \n\x0brx_waypoint\x18\x0c \x01(\x0b\x32\x0b.MeshPacket\x12\x39\n\x19node_remote_hardware_pins\x18\r \x03(\x0b\x32\x16.NodeRemoteHardwarePin\x12#\n\x0cnode_db_lite\x18\x0e \x03(\x0b\x32\r.NodeInfoLite\"\xab\x01\n\x0cNodeInfoLite\x12\x0b\n\x03num\x18\x01 \x01(\r\x12\x13\n\x04user\x18\x02 \x01(\x0b\x32\x05.User\x12\x1f\n\x08position\x18\x03 \x01(\x0b\x32\r.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\x0e.DeviceMetrics\x12\x0f\n\x07\x63hannel\x18\x07 \x01(\r\"\x85\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\x13.Position.LocSource\":\n\x0b\x43hannelFile\x12\x1a\n\x08\x63hannels\x18\x01 \x03(\x0b\x32\x08.Channel\x12\x0f\n\x07version\x18\x02 \x01(\r\"\xf6\x01\n\x08OEMStore\x12\x16\n\x0eoem_icon_width\x18\x01 \x01(\r\x12\x17\n\x0foem_icon_height\x18\x02 \x01(\r\x12\x15\n\roem_icon_bits\x18\x03 \x01(\x0c\x12\x1e\n\x08oem_font\x18\x04 \x01(\x0e\x32\x0c.ScreenFonts\x12\x10\n\x08oem_text\x18\x05 \x01(\t\x12\x13\n\x0boem_aes_key\x18\x06 \x01(\x0c\x12&\n\x10oem_local_config\x18\x07 \x01(\x0b\x32\x0c.LocalConfig\x12\x33\n\x17oem_local_module_config\x18\x08 \x01(\x0b\x32\x12.LocalModuleConfig\"J\n\x15NodeRemoteHardwarePin\x12\x10\n\x08node_num\x18\x01 \x01(\r\x12\x1f\n\x03pin\x18\x02 \x01(\x0b\x32\x12.RemoteHardwarePin*>\n\x0bScreenFonts\x12\x0e\n\nFONT_SMALL\x10\x00\x12\x0f\n\x0b\x46ONT_MEDIUM\x10\x01\x12\x0e\n\nFONT_LARGE\x10\x02\x42_\n\x13\x63om.geeksville.meshB\nDeviceOnlyZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1bmeshtastic/deviceonly.proto\x1a\x18meshtastic/channel.proto\x1a\x1ameshtastic/localonly.proto\x1a\x15meshtastic/mesh.proto\x1a\x1ameshtastic/telemetry.proto\x1a\x1emeshtastic/module_config.proto\"\xca\x02\n\x0b\x44\x65viceState\x12\x1c\n\x07my_node\x18\x02 \x01(\x0b\x32\x0b.MyNodeInfo\x12\x14\n\x05owner\x18\x03 \x01(\x0b\x32\x05.User\x12\"\n\rreceive_queue\x18\x05 \x03(\x0b\x32\x0b.MeshPacket\x12\x0f\n\x07version\x18\x08 \x01(\r\x12$\n\x0frx_text_message\x18\x07 \x01(\x0b\x32\x0b.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 \n\x0brx_waypoint\x18\x0c \x01(\x0b\x32\x0b.MeshPacket\x12\x39\n\x19node_remote_hardware_pins\x18\r \x03(\x0b\x32\x16.NodeRemoteHardwarePin\x12#\n\x0cnode_db_lite\x18\x0e \x03(\x0b\x32\r.NodeInfoLite\"\xd0\x01\n\x0cNodeInfoLite\x12\x0b\n\x03num\x18\x01 \x01(\r\x12\x13\n\x04user\x18\x02 \x01(\x0b\x32\x05.User\x12\x1f\n\x08position\x18\x03 \x01(\x0b\x32\r.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\x0e.DeviceMetrics\x12\x0f\n\x07\x63hannel\x18\x07 \x01(\r\x12\x10\n\x08via_mqtt\x18\x08 \x01(\x08\x12\x11\n\thops_away\x18\t \x01(\r\"\x85\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\x13.Position.LocSource\":\n\x0b\x43hannelFile\x12\x1a\n\x08\x63hannels\x18\x01 \x03(\x0b\x32\x08.Channel\x12\x0f\n\x07version\x18\x02 \x01(\r\"\xf6\x01\n\x08OEMStore\x12\x16\n\x0eoem_icon_width\x18\x01 \x01(\r\x12\x17\n\x0foem_icon_height\x18\x02 \x01(\r\x12\x15\n\roem_icon_bits\x18\x03 \x01(\x0c\x12\x1e\n\x08oem_font\x18\x04 \x01(\x0e\x32\x0c.ScreenFonts\x12\x10\n\x08oem_text\x18\x05 \x01(\t\x12\x13\n\x0boem_aes_key\x18\x06 \x01(\x0c\x12&\n\x10oem_local_config\x18\x07 \x01(\x0b\x32\x0c.LocalConfig\x12\x33\n\x17oem_local_module_config\x18\x08 \x01(\x0b\x32\x12.LocalModuleConfig\"J\n\x15NodeRemoteHardwarePin\x12\x10\n\x08node_num\x18\x01 \x01(\r\x12\x1f\n\x03pin\x18\x02 \x01(\x0b\x32\x12.RemoteHardwarePin*>\n\x0bScreenFonts\x12\x0e\n\nFONT_SMALL\x10\x00\x12\x0f\n\x0b\x46ONT_MEDIUM\x10\x01\x12\x0e\n\nFONT_LARGE\x10\x02\x42_\n\x13\x63om.geeksville.meshB\nDeviceOnlyZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.deviceonly_pb2', globals())
|
||||
@@ -26,18 +26,20 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\nDeviceOnlyZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
|
||||
_SCREENFONTS._serialized_start=1192
|
||||
_SCREENFONTS._serialized_end=1254
|
||||
_DEVICESTATE.fields_by_name['no_save']._options = None
|
||||
_DEVICESTATE.fields_by_name['no_save']._serialized_options = b'\030\001'
|
||||
_SCREENFONTS._serialized_start=1233
|
||||
_SCREENFONTS._serialized_end=1295
|
||||
_DEVICESTATE._serialized_start=169
|
||||
_DEVICESTATE._serialized_end=495
|
||||
_NODEINFOLITE._serialized_start=498
|
||||
_NODEINFOLITE._serialized_end=669
|
||||
_POSITIONLITE._serialized_start=672
|
||||
_POSITIONLITE._serialized_end=805
|
||||
_CHANNELFILE._serialized_start=807
|
||||
_CHANNELFILE._serialized_end=865
|
||||
_OEMSTORE._serialized_start=868
|
||||
_OEMSTORE._serialized_end=1114
|
||||
_NODEREMOTEHARDWAREPIN._serialized_start=1116
|
||||
_NODEREMOTEHARDWAREPIN._serialized_end=1190
|
||||
_DEVICESTATE._serialized_end=499
|
||||
_NODEINFOLITE._serialized_start=502
|
||||
_NODEINFOLITE._serialized_end=710
|
||||
_POSITIONLITE._serialized_start=713
|
||||
_POSITIONLITE._serialized_end=846
|
||||
_CHANNELFILE._serialized_start=848
|
||||
_CHANNELFILE._serialized_end=906
|
||||
_OEMSTORE._serialized_start=909
|
||||
_OEMSTORE._serialized_end=1155
|
||||
_NODEREMOTEHARDWAREPIN._serialized_start=1157
|
||||
_NODEREMOTEHARDWAREPIN._serialized_end=1231
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
||||
@@ -24,7 +24,7 @@ class Globals:
|
||||
def __init__(self):
|
||||
"""Constructor for the Globals CLass"""
|
||||
if Globals.__instance is not None:
|
||||
raise Exception("This class is a singleton")
|
||||
raise Exception("This class is a singleton") # pylint: disable=W0719
|
||||
else:
|
||||
Globals.__instance = self
|
||||
self.args = None
|
||||
|
||||
@@ -23,7 +23,6 @@ from meshtastic.__init__ import (
|
||||
BROADCAST_ADDR,
|
||||
BROADCAST_NUM,
|
||||
LOCAL_ADDR,
|
||||
OUR_APP_VERSION,
|
||||
ResponseHandler,
|
||||
protocols,
|
||||
publishingThread,
|
||||
@@ -48,6 +47,12 @@ class MeshInterface:
|
||||
debugOut
|
||||
"""
|
||||
|
||||
class MeshInterfaceError(Exception):
|
||||
"""An exception class for general mesh interface errors"""
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
super().__init__(self.message)
|
||||
|
||||
def __init__(self, debugOut=None, noProto=False):
|
||||
"""Constructor
|
||||
|
||||
@@ -152,13 +157,13 @@ class MeshInterface:
|
||||
)
|
||||
|
||||
rows = []
|
||||
if self.nodes:
|
||||
if self.nodesByNum:
|
||||
logging.debug(f"self.nodes:{self.nodes}")
|
||||
for node in self.nodes.values():
|
||||
for node in self.nodesByNum.values():
|
||||
if not includeSelf and node["num"] == self.localNode.nodeNum:
|
||||
continue
|
||||
|
||||
row = {"N": 0}
|
||||
row = {"N": 0, "User": f"UNK: {node['num']}", "ID": f"!{node['num']:x}"}
|
||||
|
||||
user = node.get("user")
|
||||
if user:
|
||||
@@ -314,7 +319,7 @@ class MeshInterface:
|
||||
f"mesh_pb2.Constants.DATA_PAYLOAD_LEN: {mesh_pb2.Constants.DATA_PAYLOAD_LEN}"
|
||||
)
|
||||
if len(data) > mesh_pb2.Constants.DATA_PAYLOAD_LEN:
|
||||
raise Exception("Data payload too big")
|
||||
raise MeshInterface.MeshInterfaceError("Data payload too big")
|
||||
|
||||
if (
|
||||
portNum == portnums_pb2.PortNum.UNKNOWN_APP
|
||||
@@ -440,7 +445,7 @@ class MeshInterface:
|
||||
destinationId = int(destinationId[1:], 16)
|
||||
else:
|
||||
destinationId = int(destinationId)
|
||||
|
||||
|
||||
self.sendData(
|
||||
r,
|
||||
destinationId=destinationId,
|
||||
@@ -469,7 +474,7 @@ class MeshInterface:
|
||||
)
|
||||
if telemetry.device_metrics.air_util_tx is not None:
|
||||
print(f"Transmit air utilization: {telemetry.device_metrics.air_util_tx:.2f}%")
|
||||
|
||||
|
||||
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.")
|
||||
@@ -543,25 +548,25 @@ class MeshInterface:
|
||||
and self.localNode.waitForConfig()
|
||||
)
|
||||
if not success:
|
||||
raise Exception("Timed out waiting for interface config")
|
||||
raise MeshInterface.MeshInterfaceError("Timed out waiting for interface config")
|
||||
|
||||
def waitForAckNak(self):
|
||||
"""Wait for the ack/nak"""
|
||||
success = self._timeout.waitForAckNak(self._acknowledgment)
|
||||
if not success:
|
||||
raise Exception("Timed out waiting for an acknowledgment")
|
||||
raise MeshInterface.MeshInterfaceError("Timed out waiting for an acknowledgment")
|
||||
|
||||
def waitForTraceRoute(self, waitFactor):
|
||||
"""Wait for trace route"""
|
||||
success = self._timeout.waitForTraceRoute(waitFactor, self._acknowledgment)
|
||||
if not success:
|
||||
raise Exception("Timed out waiting for traceroute")
|
||||
|
||||
raise MeshInterface.MeshInterfaceError("Timed out waiting for traceroute")
|
||||
|
||||
def waitForTelemetry(self):
|
||||
"""Wait for telemetry"""
|
||||
success = self._timeout.waitForTelemetry(self._acknowledgment)
|
||||
if not success:
|
||||
raise Exception("Timed out waiting for telemetry")
|
||||
raise MeshInterface.MeshInterfaceError("Timed out waiting for telemetry")
|
||||
|
||||
def getMyNodeInfo(self):
|
||||
"""Get info about my node."""
|
||||
@@ -591,12 +596,12 @@ class MeshInterface:
|
||||
return user.get("shortName", None)
|
||||
return None
|
||||
|
||||
def _waitConnected(self, timeout=15.0):
|
||||
def _waitConnected(self, timeout=30.0):
|
||||
"""Block until the initial node db download is complete, or timeout
|
||||
and raise an exception"""
|
||||
if not self.noProto:
|
||||
if not self.isConnected.wait(timeout): # timeout after x seconds
|
||||
raise Exception("Timed out waiting for connection completion")
|
||||
raise MeshInterface.MeshInterfaceError("Timed out waiting for connection completion")
|
||||
|
||||
# If we failed while connecting, raise the connection to the client
|
||||
if self.failure:
|
||||
@@ -605,7 +610,7 @@ class MeshInterface:
|
||||
def _generatePacketId(self):
|
||||
"""Get a new unique packet ID"""
|
||||
if self.currentPacketId is None:
|
||||
raise Exception("Not connected yet, can not generate packet")
|
||||
raise MeshInterface.MeshInterfaceError("Not connected yet, can not generate packet")
|
||||
else:
|
||||
self.currentPacketId = (self.currentPacketId + 1) & 0xFFFFFFFF
|
||||
return self.currentPacketId
|
||||
@@ -774,7 +779,7 @@ class MeshInterface:
|
||||
failmsg = None
|
||||
|
||||
if failmsg:
|
||||
self.failure = Exception(failmsg)
|
||||
self.failure = MeshInterface.MeshInterfaceError(failmsg)
|
||||
self.isConnected.set() # let waitConnected return this exception
|
||||
self.close()
|
||||
|
||||
@@ -878,6 +883,10 @@ class MeshInterface:
|
||||
self.localNode.moduleConfig.ambient_lighting.CopyFrom(
|
||||
fromRadio.moduleConfig.ambient_lighting
|
||||
)
|
||||
elif fromRadio.moduleConfig.HasField("paxcounter"):
|
||||
self.localNode.moduleConfig.paxcounter.CopyFrom(
|
||||
fromRadio.moduleConfig.paxcounter
|
||||
)
|
||||
|
||||
else:
|
||||
logging.debug("Unexpected FromRadio payload")
|
||||
@@ -916,7 +925,7 @@ class MeshInterface:
|
||||
def _getOrCreateByNum(self, nodeNum):
|
||||
"""Given a nodenum find the NodeInfo in the DB (or create if necessary)"""
|
||||
if nodeNum == BROADCAST_NUM:
|
||||
raise Exception("Can not create/find nodenum by the broadcast num")
|
||||
raise MeshInterface.MeshInterfaceError("Can not create/find nodenum by the broadcast num")
|
||||
|
||||
if nodeNum in self.nodesByNum:
|
||||
return self.nodesByNum[nodeNum]
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -12,9 +12,10 @@ _sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
from meshtastic import mesh_pb2 as meshtastic_dot_mesh__pb2
|
||||
from meshtastic import config_pb2 as meshtastic_dot_config__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15meshtastic/mqtt.proto\x1a\x15meshtastic/mesh.proto\"V\n\x0fServiceEnvelope\x12\x1b\n\x06packet\x18\x01 \x01(\x0b\x32\x0b.MeshPacket\x12\x12\n\nchannel_id\x18\x02 \x01(\t\x12\x12\n\ngateway_id\x18\x03 \x01(\tB_\n\x13\x63om.geeksville.meshB\nMQTTProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15meshtastic/mqtt.proto\x1a\x15meshtastic/mesh.proto\x1a\x17meshtastic/config.proto\"V\n\x0fServiceEnvelope\x12\x1b\n\x06packet\x18\x01 \x01(\x0b\x32\x0b.MeshPacket\x12\x12\n\nchannel_id\x18\x02 \x01(\t\x12\x12\n\ngateway_id\x18\x03 \x01(\t\"\x90\x03\n\tMapReport\x12\x11\n\tlong_name\x18\x01 \x01(\t\x12\x12\n\nshort_name\x18\x02 \x01(\t\x12\'\n\x04role\x18\x03 \x01(\x0e\x32\x19.Config.DeviceConfig.Role\x12 \n\x08hw_model\x18\x04 \x01(\x0e\x32\x0e.HardwareModel\x12\x18\n\x10\x66irmware_version\x18\x05 \x01(\t\x12-\n\x06region\x18\x06 \x01(\x0e\x32\x1d.Config.LoRaConfig.RegionCode\x12\x34\n\x0cmodem_preset\x18\x07 \x01(\x0e\x32\x1e.Config.LoRaConfig.ModemPreset\x12\x1b\n\x13has_default_channel\x18\x08 \x01(\x08\x12\x12\n\nlatitude_i\x18\t \x01(\x0f\x12\x13\n\x0blongitude_i\x18\n \x01(\x0f\x12\x10\n\x08\x61ltitude\x18\x0b \x01(\x05\x12\x1a\n\x12position_precision\x18\x0c \x01(\r\x12\x1e\n\x16num_online_local_nodes\x18\r \x01(\rB_\n\x13\x63om.geeksville.meshB\nMQTTProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.mqtt_pb2', globals())
|
||||
@@ -22,6 +23,8 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\nMQTTProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
|
||||
_SERVICEENVELOPE._serialized_start=48
|
||||
_SERVICEENVELOPE._serialized_end=134
|
||||
_SERVICEENVELOPE._serialized_start=73
|
||||
_SERVICEENVELOPE._serialized_end=159
|
||||
_MAPREPORT._serialized_start=162
|
||||
_MAPREPORT._serialized_end=562
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
||||
@@ -52,7 +52,7 @@ class Node:
|
||||
# don't show disabled channels
|
||||
if channel_pb2.Channel.Role.Name(c.role) != "DISABLED":
|
||||
print(
|
||||
f" {channel_pb2.Channel.Role.Name(c.role)} psk={pskToString(c.settings.psk)} {cStr}"
|
||||
f" Index {c.index}: {channel_pb2.Channel.Role.Name(c.role)} psk={pskToString(c.settings.psk)} {cStr}"
|
||||
)
|
||||
publicURL = self.getURL(includeAll=False)
|
||||
adminURL = self.getURL(includeAll=True)
|
||||
@@ -115,6 +115,7 @@ class Node:
|
||||
print(f"{str(camel_to_snake(field))}:\n{str(config_values)}")
|
||||
|
||||
def requestConfig(self, configType):
|
||||
"""Request the config from the node via admin message"""
|
||||
if self == self.iface.localNode:
|
||||
onResponse = None
|
||||
else:
|
||||
@@ -194,6 +195,8 @@ class Node:
|
||||
p.set_module_config.detection_sensor.CopyFrom(self.moduleConfig.detection_sensor)
|
||||
elif config_name == "ambient_lighting":
|
||||
p.set_module_config.ambient_lighting.CopyFrom(self.moduleConfig.ambient_lighting)
|
||||
elif config_name == "paxcounter":
|
||||
p.set_module_config.paxcounter.CopyFrom(self.moduleConfig.paxcounter)
|
||||
else:
|
||||
our_exit(f"Error: No valid config with name {config_name}")
|
||||
|
||||
@@ -686,16 +689,7 @@ class Node:
|
||||
logging.debug(f"Received channel {stripnl(c)}")
|
||||
index = c.index
|
||||
|
||||
# for stress testing, we can always download all channels
|
||||
fastChannelDownload = True
|
||||
|
||||
# Once we see a response that has NO settings, assume
|
||||
# we are at the end of channels and stop fetching
|
||||
quitEarly = (
|
||||
c.role == channel_pb2.Channel.Role.DISABLED
|
||||
) and fastChannelDownload
|
||||
|
||||
if quitEarly or index >= 8 - 1:
|
||||
if index >= 8 - 1:
|
||||
logging.debug("Finished downloading channels")
|
||||
|
||||
self.channels = self.partialChannels
|
||||
@@ -707,6 +701,7 @@ class Node:
|
||||
self._requestChannel(index + 1)
|
||||
|
||||
def onAckNak(self, p):
|
||||
"""Informative handler for ACK/NAK responses"""
|
||||
if p["decoded"]["routing"]["errorReason"] != "NONE":
|
||||
print(
|
||||
f'Received a NAK, error reason: {p["decoded"]["routing"]["errorReason"]}'
|
||||
|
||||
@@ -13,7 +13,7 @@ _sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19meshtastic/portnums.proto*\xe8\x03\n\x07PortNum\x12\x0f\n\x0bUNKNOWN_APP\x10\x00\x12\x14\n\x10TEXT_MESSAGE_APP\x10\x01\x12\x17\n\x13REMOTE_HARDWARE_APP\x10\x02\x12\x10\n\x0cPOSITION_APP\x10\x03\x12\x10\n\x0cNODEINFO_APP\x10\x04\x12\x0f\n\x0bROUTING_APP\x10\x05\x12\r\n\tADMIN_APP\x10\x06\x12\x1f\n\x1bTEXT_MESSAGE_COMPRESSED_APP\x10\x07\x12\x10\n\x0cWAYPOINT_APP\x10\x08\x12\r\n\tAUDIO_APP\x10\t\x12\x18\n\x14\x44\x45TECTION_SENSOR_APP\x10\n\x12\r\n\tREPLY_APP\x10 \x12\x11\n\rIP_TUNNEL_APP\x10!\x12\x12\n\x0ePAXCOUNTER_APP\x10\"\x12\x0e\n\nSERIAL_APP\x10@\x12\x15\n\x11STORE_FORWARD_APP\x10\x41\x12\x12\n\x0eRANGE_TEST_APP\x10\x42\x12\x11\n\rTELEMETRY_APP\x10\x43\x12\x0b\n\x07ZPS_APP\x10\x44\x12\x11\n\rSIMULATOR_APP\x10\x45\x12\x12\n\x0eTRACEROUTE_APP\x10\x46\x12\x14\n\x10NEIGHBORINFO_APP\x10G\x12\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\x19meshtastic/portnums.proto*\x8d\x04\n\x07PortNum\x12\x0f\n\x0bUNKNOWN_APP\x10\x00\x12\x14\n\x10TEXT_MESSAGE_APP\x10\x01\x12\x17\n\x13REMOTE_HARDWARE_APP\x10\x02\x12\x10\n\x0cPOSITION_APP\x10\x03\x12\x10\n\x0cNODEINFO_APP\x10\x04\x12\x0f\n\x0bROUTING_APP\x10\x05\x12\r\n\tADMIN_APP\x10\x06\x12\x1f\n\x1bTEXT_MESSAGE_COMPRESSED_APP\x10\x07\x12\x10\n\x0cWAYPOINT_APP\x10\x08\x12\r\n\tAUDIO_APP\x10\t\x12\x18\n\x14\x44\x45TECTION_SENSOR_APP\x10\n\x12\r\n\tREPLY_APP\x10 \x12\x11\n\rIP_TUNNEL_APP\x10!\x12\x12\n\x0ePAXCOUNTER_APP\x10\"\x12\x0e\n\nSERIAL_APP\x10@\x12\x15\n\x11STORE_FORWARD_APP\x10\x41\x12\x12\n\x0eRANGE_TEST_APP\x10\x42\x12\x11\n\rTELEMETRY_APP\x10\x43\x12\x0b\n\x07ZPS_APP\x10\x44\x12\x11\n\rSIMULATOR_APP\x10\x45\x12\x12\n\x0eTRACEROUTE_APP\x10\x46\x12\x14\n\x10NEIGHBORINFO_APP\x10G\x12\x0f\n\x0b\x41TAK_PLUGIN\x10H\x12\x12\n\x0eMAP_REPORT_APP\x10I\x12\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')
|
||||
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.portnums_pb2', 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'
|
||||
_PORTNUM._serialized_start=30
|
||||
_PORTNUM._serialized_end=518
|
||||
_PORTNUM._serialized_end=555
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
||||
@@ -32,7 +32,8 @@ class SerialInterface(StreamInterface):
|
||||
ports = meshtastic.util.findPorts(True)
|
||||
logging.debug(f"ports:{ports}")
|
||||
if len(ports) == 0:
|
||||
meshtastic.util.our_exit("Warning: No Meshtastic devices detected.")
|
||||
print("No Serial Meshtastic device detected, attempting TCP connection on localhost.")
|
||||
return
|
||||
elif len(ports) > 1:
|
||||
message = "Warning: Multiple serial ports were detected so one serial port must be specified with the '--port'.\n"
|
||||
message += f" Ports detected:{ports}"
|
||||
|
||||
@@ -13,7 +13,7 @@ _sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1dmeshtastic/storeforward.proto\"\xbe\x06\n\x0fStoreAndForward\x12,\n\x02rr\x18\x01 \x01(\x0e\x32 .StoreAndForward.RequestResponse\x12,\n\x05stats\x18\x02 \x01(\x0b\x32\x1b.StoreAndForward.StatisticsH\x00\x12+\n\x07history\x18\x03 \x01(\x0b\x32\x18.StoreAndForward.HistoryH\x00\x12/\n\theartbeat\x18\x04 \x01(\x0b\x32\x1a.StoreAndForward.HeartbeatH\x00\x12\x0f\n\x05\x65mpty\x18\x05 \x01(\x08H\x00\x1a\xcd\x01\n\nStatistics\x12\x16\n\x0emessages_total\x18\x01 \x01(\r\x12\x16\n\x0emessages_saved\x18\x02 \x01(\r\x12\x14\n\x0cmessages_max\x18\x03 \x01(\r\x12\x0f\n\x07up_time\x18\x04 \x01(\r\x12\x10\n\x08requests\x18\x05 \x01(\r\x12\x18\n\x10requests_history\x18\x06 \x01(\r\x12\x11\n\theartbeat\x18\x07 \x01(\x08\x12\x12\n\nreturn_max\x18\x08 \x01(\r\x12\x15\n\rreturn_window\x18\t \x01(\r\x1aI\n\x07History\x12\x18\n\x10history_messages\x18\x01 \x01(\r\x12\x0e\n\x06window\x18\x02 \x01(\r\x12\x14\n\x0clast_request\x18\x03 \x01(\r\x1a.\n\tHeartbeat\x12\x0e\n\x06period\x18\x01 \x01(\r\x12\x11\n\tsecondary\x18\x02 \x01(\r\"\x89\x02\n\x0fRequestResponse\x12\t\n\x05UNSET\x10\x00\x12\x10\n\x0cROUTER_ERROR\x10\x01\x12\x14\n\x10ROUTER_HEARTBEAT\x10\x02\x12\x0f\n\x0bROUTER_PING\x10\x03\x12\x0f\n\x0bROUTER_PONG\x10\x04\x12\x0f\n\x0bROUTER_BUSY\x10\x05\x12\x12\n\x0eROUTER_HISTORY\x10\x06\x12\x10\n\x0cROUTER_STATS\x10\x07\x12\x10\n\x0c\x43LIENT_ERROR\x10@\x12\x12\n\x0e\x43LIENT_HISTORY\x10\x41\x12\x10\n\x0c\x43LIENT_STATS\x10\x42\x12\x0f\n\x0b\x43LIENT_PING\x10\x43\x12\x0f\n\x0b\x43LIENT_PONG\x10\x44\x12\x10\n\x0c\x43LIENT_ABORT\x10jB\t\n\x07variantBj\n\x13\x63om.geeksville.meshB\x15StoreAndForwardProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1dmeshtastic/storeforward.proto\"\xf0\x06\n\x0fStoreAndForward\x12,\n\x02rr\x18\x01 \x01(\x0e\x32 .StoreAndForward.RequestResponse\x12,\n\x05stats\x18\x02 \x01(\x0b\x32\x1b.StoreAndForward.StatisticsH\x00\x12+\n\x07history\x18\x03 \x01(\x0b\x32\x18.StoreAndForward.HistoryH\x00\x12/\n\theartbeat\x18\x04 \x01(\x0b\x32\x1a.StoreAndForward.HeartbeatH\x00\x12\x0e\n\x04text\x18\x05 \x01(\x0cH\x00\x1a\xcd\x01\n\nStatistics\x12\x16\n\x0emessages_total\x18\x01 \x01(\r\x12\x16\n\x0emessages_saved\x18\x02 \x01(\r\x12\x14\n\x0cmessages_max\x18\x03 \x01(\r\x12\x0f\n\x07up_time\x18\x04 \x01(\r\x12\x10\n\x08requests\x18\x05 \x01(\r\x12\x18\n\x10requests_history\x18\x06 \x01(\r\x12\x11\n\theartbeat\x18\x07 \x01(\x08\x12\x12\n\nreturn_max\x18\x08 \x01(\r\x12\x15\n\rreturn_window\x18\t \x01(\r\x1aI\n\x07History\x12\x18\n\x10history_messages\x18\x01 \x01(\r\x12\x0e\n\x06window\x18\x02 \x01(\r\x12\x14\n\x0clast_request\x18\x03 \x01(\r\x1a.\n\tHeartbeat\x12\x0e\n\x06period\x18\x01 \x01(\r\x12\x11\n\tsecondary\x18\x02 \x01(\r\"\xbc\x02\n\x0fRequestResponse\x12\t\n\x05UNSET\x10\x00\x12\x10\n\x0cROUTER_ERROR\x10\x01\x12\x14\n\x10ROUTER_HEARTBEAT\x10\x02\x12\x0f\n\x0bROUTER_PING\x10\x03\x12\x0f\n\x0bROUTER_PONG\x10\x04\x12\x0f\n\x0bROUTER_BUSY\x10\x05\x12\x12\n\x0eROUTER_HISTORY\x10\x06\x12\x10\n\x0cROUTER_STATS\x10\x07\x12\x16\n\x12ROUTER_TEXT_DIRECT\x10\x08\x12\x19\n\x15ROUTER_TEXT_BROADCAST\x10\t\x12\x10\n\x0c\x43LIENT_ERROR\x10@\x12\x12\n\x0e\x43LIENT_HISTORY\x10\x41\x12\x10\n\x0c\x43LIENT_STATS\x10\x42\x12\x0f\n\x0b\x43LIENT_PING\x10\x43\x12\x0f\n\x0b\x43LIENT_PONG\x10\x44\x12\x10\n\x0c\x43LIENT_ABORT\x10jB\t\n\x07variantBj\n\x13\x63om.geeksville.meshB\x15StoreAndForwardProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.storeforward_pb2', globals())
|
||||
@@ -22,13 +22,13 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\025StoreAndForwardProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
|
||||
_STOREANDFORWARD._serialized_start=34
|
||||
_STOREANDFORWARD._serialized_end=864
|
||||
_STOREANDFORWARD_STATISTICS._serialized_start=257
|
||||
_STOREANDFORWARD_STATISTICS._serialized_end=462
|
||||
_STOREANDFORWARD_HISTORY._serialized_start=464
|
||||
_STOREANDFORWARD_HISTORY._serialized_end=537
|
||||
_STOREANDFORWARD_HEARTBEAT._serialized_start=539
|
||||
_STOREANDFORWARD_HEARTBEAT._serialized_end=585
|
||||
_STOREANDFORWARD_REQUESTRESPONSE._serialized_start=588
|
||||
_STOREANDFORWARD_REQUESTRESPONSE._serialized_end=853
|
||||
_STOREANDFORWARD._serialized_end=914
|
||||
_STOREANDFORWARD_STATISTICS._serialized_start=256
|
||||
_STOREANDFORWARD_STATISTICS._serialized_end=461
|
||||
_STOREANDFORWARD_HISTORY._serialized_start=463
|
||||
_STOREANDFORWARD_HISTORY._serialized_end=536
|
||||
_STOREANDFORWARD_HEARTBEAT._serialized_start=538
|
||||
_STOREANDFORWARD_HEARTBEAT._serialized_end=584
|
||||
_STOREANDFORWARD_REQUESTRESPONSE._serialized_start=587
|
||||
_STOREANDFORWARD_REQUESTRESPONSE._serialized_end=903
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
||||
@@ -32,7 +32,7 @@ class StreamInterface(MeshInterface):
|
||||
"""
|
||||
|
||||
if not hasattr(self, "stream") and not noProto:
|
||||
raise Exception(
|
||||
raise Exception( # pylint: disable=W0719
|
||||
"StreamInterface is now abstract (to update existing code create SerialInterface instead)"
|
||||
)
|
||||
self._rxBuf = bytes() # empty
|
||||
|
||||
@@ -13,7 +13,7 @@ _sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1ameshtastic/telemetry.proto\"i\n\rDeviceMetrics\x12\x15\n\rbattery_level\x18\x01 \x01(\r\x12\x0f\n\x07voltage\x18\x02 \x01(\x02\x12\x1b\n\x13\x63hannel_utilization\x18\x03 \x01(\x02\x12\x13\n\x0b\x61ir_util_tx\x18\x04 \x01(\x02\"\x9b\x01\n\x12\x45nvironmentMetrics\x12\x13\n\x0btemperature\x18\x01 \x01(\x02\x12\x19\n\x11relative_humidity\x18\x02 \x01(\x02\x12\x1b\n\x13\x62\x61rometric_pressure\x18\x03 \x01(\x02\x12\x16\n\x0egas_resistance\x18\x04 \x01(\x02\x12\x0f\n\x07voltage\x18\x05 \x01(\x02\x12\x0f\n\x07\x63urrent\x18\x06 \x01(\x02\"\x8c\x01\n\x0cPowerMetrics\x12\x13\n\x0b\x63h1_voltage\x18\x01 \x01(\x02\x12\x13\n\x0b\x63h1_current\x18\x02 \x01(\x02\x12\x13\n\x0b\x63h2_voltage\x18\x03 \x01(\x02\x12\x13\n\x0b\x63h2_current\x18\x04 \x01(\x02\x12\x13\n\x0b\x63h3_voltage\x18\x05 \x01(\x02\x12\x13\n\x0b\x63h3_current\x18\x06 \x01(\x02\"\xbf\x02\n\x11\x41irQualityMetrics\x12\x15\n\rpm10_standard\x18\x01 \x01(\r\x12\x15\n\rpm25_standard\x18\x02 \x01(\r\x12\x16\n\x0epm100_standard\x18\x03 \x01(\r\x12\x1a\n\x12pm10_environmental\x18\x04 \x01(\r\x12\x1a\n\x12pm25_environmental\x18\x05 \x01(\r\x12\x1b\n\x13pm100_environmental\x18\x06 \x01(\r\x12\x16\n\x0eparticles_03um\x18\x07 \x01(\r\x12\x16\n\x0eparticles_05um\x18\x08 \x01(\r\x12\x16\n\x0eparticles_10um\x18\t \x01(\r\x12\x16\n\x0eparticles_25um\x18\n \x01(\r\x12\x16\n\x0eparticles_50um\x18\x0b \x01(\r\x12\x17\n\x0fparticles_100um\x18\x0c \x01(\r\"\xdd\x01\n\tTelemetry\x12\x0c\n\x04time\x18\x01 \x01(\x07\x12(\n\x0e\x64\x65vice_metrics\x18\x02 \x01(\x0b\x32\x0e.DeviceMetricsH\x00\x12\x32\n\x13\x65nvironment_metrics\x18\x03 \x01(\x0b\x32\x13.EnvironmentMetricsH\x00\x12\x31\n\x13\x61ir_quality_metrics\x18\x04 \x01(\x0b\x32\x12.AirQualityMetricsH\x00\x12&\n\rpower_metrics\x18\x05 \x01(\x0b\x32\r.PowerMetricsH\x00\x42\t\n\x07variant*\xd4\x01\n\x13TelemetrySensorType\x12\x10\n\x0cSENSOR_UNSET\x10\x00\x12\n\n\x06\x42ME280\x10\x01\x12\n\n\x06\x42ME680\x10\x02\x12\x0b\n\x07MCP9808\x10\x03\x12\n\n\x06INA260\x10\x04\x12\n\n\x06INA219\x10\x05\x12\n\n\x06\x42MP280\x10\x06\x12\t\n\x05SHTC3\x10\x07\x12\t\n\x05LPS22\x10\x08\x12\x0b\n\x07QMC6310\x10\t\x12\x0b\n\x07QMI8658\x10\n\x12\x0c\n\x08QMC5883L\x10\x0b\x12\t\n\x05SHT31\x10\x0c\x12\x0c\n\x08PMSA003I\x10\r\x12\x0b\n\x07INA3221\x10\x0e\x42\x64\n\x13\x63om.geeksville.meshB\x0fTelemetryProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1ameshtastic/telemetry.proto\"i\n\rDeviceMetrics\x12\x15\n\rbattery_level\x18\x01 \x01(\r\x12\x0f\n\x07voltage\x18\x02 \x01(\x02\x12\x1b\n\x13\x63hannel_utilization\x18\x03 \x01(\x02\x12\x13\n\x0b\x61ir_util_tx\x18\x04 \x01(\x02\"\x9b\x01\n\x12\x45nvironmentMetrics\x12\x13\n\x0btemperature\x18\x01 \x01(\x02\x12\x19\n\x11relative_humidity\x18\x02 \x01(\x02\x12\x1b\n\x13\x62\x61rometric_pressure\x18\x03 \x01(\x02\x12\x16\n\x0egas_resistance\x18\x04 \x01(\x02\x12\x0f\n\x07voltage\x18\x05 \x01(\x02\x12\x0f\n\x07\x63urrent\x18\x06 \x01(\x02\"\x8c\x01\n\x0cPowerMetrics\x12\x13\n\x0b\x63h1_voltage\x18\x01 \x01(\x02\x12\x13\n\x0b\x63h1_current\x18\x02 \x01(\x02\x12\x13\n\x0b\x63h2_voltage\x18\x03 \x01(\x02\x12\x13\n\x0b\x63h2_current\x18\x04 \x01(\x02\x12\x13\n\x0b\x63h3_voltage\x18\x05 \x01(\x02\x12\x13\n\x0b\x63h3_current\x18\x06 \x01(\x02\"\xbf\x02\n\x11\x41irQualityMetrics\x12\x15\n\rpm10_standard\x18\x01 \x01(\r\x12\x15\n\rpm25_standard\x18\x02 \x01(\r\x12\x16\n\x0epm100_standard\x18\x03 \x01(\r\x12\x1a\n\x12pm10_environmental\x18\x04 \x01(\r\x12\x1a\n\x12pm25_environmental\x18\x05 \x01(\r\x12\x1b\n\x13pm100_environmental\x18\x06 \x01(\r\x12\x16\n\x0eparticles_03um\x18\x07 \x01(\r\x12\x16\n\x0eparticles_05um\x18\x08 \x01(\r\x12\x16\n\x0eparticles_10um\x18\t \x01(\r\x12\x16\n\x0eparticles_25um\x18\n \x01(\r\x12\x16\n\x0eparticles_50um\x18\x0b \x01(\r\x12\x17\n\x0fparticles_100um\x18\x0c \x01(\r\"\xdd\x01\n\tTelemetry\x12\x0c\n\x04time\x18\x01 \x01(\x07\x12(\n\x0e\x64\x65vice_metrics\x18\x02 \x01(\x0b\x32\x0e.DeviceMetricsH\x00\x12\x32\n\x13\x65nvironment_metrics\x18\x03 \x01(\x0b\x32\x13.EnvironmentMetricsH\x00\x12\x31\n\x13\x61ir_quality_metrics\x18\x04 \x01(\x0b\x32\x12.AirQualityMetricsH\x00\x12&\n\rpower_metrics\x18\x05 \x01(\x0b\x32\r.PowerMetricsH\x00\x42\t\n\x07variant*\xe0\x01\n\x13TelemetrySensorType\x12\x10\n\x0cSENSOR_UNSET\x10\x00\x12\n\n\x06\x42ME280\x10\x01\x12\n\n\x06\x42ME680\x10\x02\x12\x0b\n\x07MCP9808\x10\x03\x12\n\n\x06INA260\x10\x04\x12\n\n\x06INA219\x10\x05\x12\n\n\x06\x42MP280\x10\x06\x12\t\n\x05SHTC3\x10\x07\x12\t\n\x05LPS22\x10\x08\x12\x0b\n\x07QMC6310\x10\t\x12\x0b\n\x07QMI8658\x10\n\x12\x0c\n\x08QMC5883L\x10\x0b\x12\t\n\x05SHT31\x10\x0c\x12\x0c\n\x08PMSA003I\x10\r\x12\x0b\n\x07INA3221\x10\x0e\x12\n\n\x06\x42MP085\x10\x0f\x42\x64\n\x13\x63om.geeksville.meshB\x0fTelemetryProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
|
||||
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.telemetry_pb2', globals())
|
||||
@@ -22,7 +22,7 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\017TelemetryProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
|
||||
_TELEMETRYSENSORTYPE._serialized_start=985
|
||||
_TELEMETRYSENSORTYPE._serialized_end=1197
|
||||
_TELEMETRYSENSORTYPE._serialized_end=1209
|
||||
_DEVICEMETRICS._serialized_start=30
|
||||
_DEVICEMETRICS._serialized_end=135
|
||||
_ENVIRONMENTMETRICS._serialized_start=138
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
"""Meshtastic unit tests for ble_interface.py"""
|
||||
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from ..ble_interface import BLEInterface
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@patch("platform.system", return_value="Linux")
|
||||
def test_BLEInterface(mock_platform):
|
||||
"""Test that we can instantiate a BLEInterface"""
|
||||
iface = BLEInterface("foo", debugOut=True, noProto=True)
|
||||
iface.close()
|
||||
mock_platform.assert_called()
|
||||
@@ -23,7 +23,7 @@ from meshtastic.__main__ import (
|
||||
tunnelMain,
|
||||
)
|
||||
|
||||
from ..channel_pb2 import Channel
|
||||
from ..channel_pb2 import Channel # pylint: disable=E0611
|
||||
|
||||
# from ..ble_interface import BLEInterface
|
||||
from ..node import Node
|
||||
@@ -283,26 +283,6 @@ def test_main_info_with_tcp_interface(capsys):
|
||||
mo.assert_called()
|
||||
|
||||
|
||||
# TODO: comment out ble (for now)
|
||||
# @pytest.mark.unit
|
||||
# def test_main_info_with_ble_interface(capsys):
|
||||
# """Test --info"""
|
||||
# sys.argv = ['', '--info', '--ble', 'foo']
|
||||
# Globals.getInstance().set_args(sys.argv)
|
||||
#
|
||||
# iface = MagicMock(autospec=BLEInterface)
|
||||
# def mock_showInfo():
|
||||
# print('inside mocked showInfo')
|
||||
# iface.showInfo.side_effect = mock_showInfo
|
||||
# with patch('meshtastic.ble_interface.BLEInterface', return_value=iface) as mo:
|
||||
# main()
|
||||
# out, err = capsys.readouterr()
|
||||
# assert re.search(r'Connected to radio', out, re.MULTILINE)
|
||||
# assert re.search(r'inside mocked showInfo', out, re.MULTILINE)
|
||||
# assert err == ''
|
||||
# mo.assert_called()
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.usefixtures("reset_globals")
|
||||
def test_main_no_proto(capsys):
|
||||
@@ -408,7 +388,7 @@ def test_main_onConnected_exception(capsys):
|
||||
Globals.getInstance().set_args(sys.argv)
|
||||
|
||||
def throw_an_exception(junk):
|
||||
raise Exception("Fake exception.")
|
||||
raise Exception("Fake exception.") # pylint: disable=W0719
|
||||
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
with patch("meshtastic.serial_interface.SerialInterface", return_value=iface):
|
||||
|
||||
@@ -7,7 +7,7 @@ from unittest.mock import MagicMock, patch
|
||||
import pytest
|
||||
|
||||
# from ..admin_pb2 import AdminMessage
|
||||
from ..channel_pb2 import Channel
|
||||
from ..channel_pb2 import Channel # pylint: disable=E0611
|
||||
from ..node import Node
|
||||
from ..serial_interface import SerialInterface
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@ def test_catchAndIgnore(caplog):
|
||||
"""Test catchAndIgnore() does not actually throw an exception, but just logs"""
|
||||
|
||||
def some_closure():
|
||||
raise Exception("foo")
|
||||
raise Exception("foo") # pylint: disable=W0719
|
||||
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
catchAndIgnore("something", some_closure)
|
||||
|
||||
@@ -38,6 +38,12 @@ def onTunnelReceive(packet, interface): # pylint: disable=W0613
|
||||
class Tunnel:
|
||||
"""A TUN based IP tunnel over meshtastic"""
|
||||
|
||||
class TunnelError(Exception):
|
||||
"""An exception class for general tunnel errors"""
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
super().__init__(self.message)
|
||||
|
||||
def __init__(self, iface, subnet="10.115", netmask="255.255.0.0"):
|
||||
"""
|
||||
Constructor
|
||||
@@ -47,19 +53,19 @@ class Tunnel:
|
||||
"""
|
||||
|
||||
if not iface:
|
||||
raise Exception("Tunnel() must have a interface")
|
||||
raise Tunnel.TunnelError("Tunnel() must have a interface")
|
||||
|
||||
if not subnet:
|
||||
raise Exception("Tunnel() must have a subnet")
|
||||
raise Tunnel.TunnelError("Tunnel() must have a subnet")
|
||||
|
||||
if not netmask:
|
||||
raise Exception("Tunnel() must have a netmask")
|
||||
raise Tunnel.TunnelError("Tunnel() must have a netmask")
|
||||
|
||||
self.iface = iface
|
||||
self.subnetPrefix = subnet
|
||||
|
||||
if platform.system() != "Linux":
|
||||
raise Exception("Tunnel() can only be run instantiated on a Linux system")
|
||||
raise Tunnel.TunnelError("Tunnel() can only be run instantiated on a Linux system")
|
||||
|
||||
our_globals = Globals.getInstance()
|
||||
our_globals.set_tunnelInstance(self)
|
||||
|
||||
@@ -12,12 +12,13 @@ import time
|
||||
import traceback
|
||||
from queue import Queue
|
||||
|
||||
import pkg_resources
|
||||
import packaging.version as pkg_version
|
||||
import requests
|
||||
import serial
|
||||
import serial.tools.list_ports
|
||||
|
||||
from meshtastic.supported_device import supported_devices
|
||||
from meshtastic.version import get_active_version
|
||||
|
||||
"""Some devices such as a seger jlink we never want to accidentally open"""
|
||||
blacklistVids = dict.fromkeys([0x1366])
|
||||
@@ -108,7 +109,7 @@ def stripnl(s):
|
||||
|
||||
def fixme(message):
|
||||
"""Raise an exception for things that needs to be fixed"""
|
||||
raise Exception(f"FIXME: {message}")
|
||||
raise Exception(f"FIXME: {message}") # pylint: disable=W0719
|
||||
|
||||
|
||||
def catchAndIgnore(reason, closure):
|
||||
@@ -192,7 +193,7 @@ class Timeout:
|
||||
return True
|
||||
time.sleep(self.sleepInterval)
|
||||
return False
|
||||
|
||||
|
||||
def waitForTelemetry(self, acknowledgment):
|
||||
"""Block until telemetry response is received. Returns True if telemetry response has been received."""
|
||||
self.reset()
|
||||
@@ -269,7 +270,7 @@ def support_info():
|
||||
print(f" Machine: {platform.uname().machine}")
|
||||
print(f" Encoding (stdin): {sys.stdin.encoding}")
|
||||
print(f" Encoding (stdout): {sys.stdout.encoding}")
|
||||
the_version = pkg_resources.get_distribution("meshtastic").version
|
||||
the_version = get_active_version()
|
||||
pypi_version = check_if_newer_version()
|
||||
if pypi_version:
|
||||
print(
|
||||
@@ -599,9 +600,15 @@ def check_if_newer_version():
|
||||
pypi_version = data["info"]["version"]
|
||||
except Exception:
|
||||
pass
|
||||
act_version = pkg_resources.get_distribution("meshtastic").version
|
||||
if pypi_version and pkg_resources.parse_version(
|
||||
pypi_version
|
||||
) <= pkg_resources.parse_version(act_version):
|
||||
act_version = get_active_version()
|
||||
|
||||
try:
|
||||
parsed_act_version = pkg_version.parse(act_version)
|
||||
parsed_pypi_version = pkg_version.parse(pypi_version)
|
||||
except pkg_version.InvalidVersion:
|
||||
return pypi_version
|
||||
|
||||
if parsed_pypi_version <= parsed_act_version:
|
||||
return None
|
||||
|
||||
return pypi_version
|
||||
|
||||
13
meshtastic/version.py
Normal file
13
meshtastic/version.py
Normal file
@@ -0,0 +1,13 @@
|
||||
"""Version lookup utilities, isolated for cleanliness"""
|
||||
import sys
|
||||
try:
|
||||
from importlib.metadata import version
|
||||
except:
|
||||
import pkg_resources
|
||||
|
||||
def get_active_version():
|
||||
"""Get the currently active version using importlib, or pkg_resources if we must"""
|
||||
if "importlib.metadata" in sys.modules:
|
||||
return version("meshtastic")
|
||||
else:
|
||||
return pkg_resources.get_distribution("meshtastic").version # pylint: disable=E0601
|
||||
Submodule protobufs updated: 4a1d3766e8...556e49ba61
@@ -18,4 +18,5 @@ pyyaml
|
||||
pytap2
|
||||
pdoc3
|
||||
pypubsub
|
||||
pygatt; platform_system == "Linux"
|
||||
bleak
|
||||
packaging
|
||||
|
||||
5
setup.py
5
setup.py
@@ -13,7 +13,7 @@ with open("README.md", "r") as fh:
|
||||
# This call to setup() does all the work
|
||||
setup(
|
||||
name="meshtastic",
|
||||
version="2.2.17",
|
||||
version="2.3.0",
|
||||
description="Python API & client shell for talking to Meshtastic devices",
|
||||
long_description=long_description,
|
||||
long_description_content_type="text/markdown",
|
||||
@@ -43,7 +43,8 @@ setup(
|
||||
"tabulate>=0.8.9",
|
||||
"timeago>=1.0.15",
|
||||
"pyyaml",
|
||||
"pygatt>=4.0.5 ; platform_system=='Linux'",
|
||||
"bleak>=0.21.1",
|
||||
"packaging",
|
||||
],
|
||||
extras_require={"tunnel": ["pytap2>=2.0.0"]},
|
||||
python_requires=">=3.7",
|
||||
|
||||
Reference in New Issue
Block a user