mirror of
https://github.com/meshtastic/python.git
synced 2026-01-02 04:47:54 -05:00
cleanup localNode, to prepare for remote settings operations
This commit is contained in:
@@ -57,21 +57,13 @@ interface = meshtastic.SerialInterface()
|
||||
|
||||
import pygatt
|
||||
import google.protobuf.json_format
|
||||
import serial
|
||||
import threading
|
||||
import logging
|
||||
import sys
|
||||
import random
|
||||
import traceback
|
||||
import time
|
||||
import base64
|
||||
import platform
|
||||
import socket
|
||||
import serial, threading, logging, sys, random, traceback, time, base64, platform, socket
|
||||
from . import mesh_pb2, portnums_pb2, apponly_pb2, admin_pb2, environmental_measurement_pb2, remote_hardware_pb2, channel_pb2, radioconfig_pb2, util
|
||||
from .util import fixme, catchAndIgnore, stripnl
|
||||
from pubsub import pub
|
||||
from dotmap import DotMap
|
||||
from typing import *
|
||||
from google.protobuf.json_format import MessageToJson
|
||||
|
||||
START1 = 0x94
|
||||
START2 = 0xc3
|
||||
@@ -110,6 +102,206 @@ class KnownProtocol(NamedTuple):
|
||||
onReceive: Callable = None
|
||||
|
||||
|
||||
def waitForSet(target, sleep=.1, maxsecs=20, attrs=()):
|
||||
"""Block until the specified attributes are set. Returns True if config has been received."""
|
||||
for _ in range(int(maxsecs/sleep)):
|
||||
if all(map(lambda a: getattr(target, a, None), attrs)):
|
||||
return True
|
||||
time.sleep(sleep)
|
||||
return False
|
||||
|
||||
|
||||
class Node:
|
||||
"""A model of a (local or remote) node in the mesh
|
||||
|
||||
Includes methods for radioConfig and channels
|
||||
"""
|
||||
|
||||
def __init__(self, iface, nodeNum):
|
||||
"""Constructor"""
|
||||
self.iface = iface
|
||||
self.nodeNum = nodeNum
|
||||
self.radioConfig = None
|
||||
self.channels = None
|
||||
|
||||
def showInfo(self):
|
||||
"""Show human readable description of our node"""
|
||||
print(self.radioConfig)
|
||||
print("Channels:")
|
||||
for c in self.channels:
|
||||
if c.role != channel_pb2.Channel.Role.DISABLED:
|
||||
cStr = MessageToJson(c.settings).replace("\n", "")
|
||||
print(f" {channel_pb2.Channel.Role.Name(c.role)} {cStr}")
|
||||
print(f"\nChannel URL {self.channelURL}")
|
||||
|
||||
def requestConfig(self):
|
||||
"""
|
||||
Send regular MeshPackets to ask for settings and channels
|
||||
"""
|
||||
self.radioConfig = None
|
||||
self.channels = None
|
||||
self.partialChannels = [] # We keep our channels in a temp array until finished
|
||||
|
||||
self._requestSettings()
|
||||
self._requestChannel(0)
|
||||
|
||||
def waitForConfig(self):
|
||||
"""Block until radio config is received. Returns True if config has been received."""
|
||||
return waitForSet(self, attrs=('radioConfig', 'channels'))
|
||||
|
||||
def writeConfig(self):
|
||||
"""Write the current (edited) radioConfig to the device"""
|
||||
if self.radioConfig == None:
|
||||
raise Exception("No RadioConfig has been read")
|
||||
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_radio.CopyFrom(self.radioConfig)
|
||||
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote config")
|
||||
|
||||
def writeChannel(self, channelIndex):
|
||||
"""Write the current (edited) channel to the device"""
|
||||
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_channel.CopyFrom(self.channels[channelIndex])
|
||||
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote channel {channelIndex}")
|
||||
|
||||
def setOwner(self, long_name, short_name=None):
|
||||
"""Set device owner name"""
|
||||
nChars = 3
|
||||
minChars = 2
|
||||
if long_name is not None:
|
||||
long_name = long_name.strip()
|
||||
if short_name is None:
|
||||
words = long_name.split()
|
||||
if len(long_name) <= nChars:
|
||||
short_name = long_name
|
||||
elif len(words) >= minChars:
|
||||
short_name = ''.join(map(lambda word: word[0], words))
|
||||
else:
|
||||
trans = str.maketrans(dict.fromkeys('aeiouAEIOU'))
|
||||
short_name = long_name[0] + long_name[1:].translate(trans)
|
||||
if len(short_name) < nChars:
|
||||
short_name = long_name[:nChars]
|
||||
|
||||
p = admin_pb2.AdminMessage()
|
||||
|
||||
if long_name is not None:
|
||||
p.set_owner.long_name = long_name
|
||||
if short_name is not None:
|
||||
short_name = short_name.strip()
|
||||
if len(short_name) > nChars:
|
||||
short_name = short_name[:nChars]
|
||||
p.set_owner.short_name = short_name
|
||||
|
||||
return self._sendAdmin(p)
|
||||
|
||||
@property
|
||||
def channelURL(self):
|
||||
"""The sharable URL that describes the current channel
|
||||
"""
|
||||
# Only keep the primary/secondary channels, assume primary is first
|
||||
channelSet = apponly_pb2.ChannelSet()
|
||||
for c in self.channels:
|
||||
if c.role != channel_pb2.Channel.Role.DISABLED:
|
||||
channelSet.settings.append(c.settings)
|
||||
bytes = channelSet.SerializeToString()
|
||||
s = base64.urlsafe_b64encode(bytes).decode('ascii')
|
||||
return f"https://www.meshtastic.org/d/#{s}".replace("=", "")
|
||||
|
||||
def setURL(self, url):
|
||||
"""Set mesh network URL"""
|
||||
if self.radioConfig == None:
|
||||
raise Exception("No RadioConfig has been read")
|
||||
|
||||
# URLs are of the form https://www.meshtastic.org/d/#{base64_channel_set}
|
||||
# Split on '/#' to find the base64 encoded channel settings
|
||||
splitURL = url.split("/#")
|
||||
b64 = splitURL[-1]
|
||||
|
||||
# We normally strip padding to make for a shorter URL, but the python parser doesn't like
|
||||
# that. So add back any missing padding
|
||||
# per https://stackoverflow.com/a/9807138
|
||||
missing_padding = len(b64) % 4
|
||||
if missing_padding:
|
||||
b64 += '=' * (4 - missing_padding)
|
||||
|
||||
decodedURL = base64.urlsafe_b64decode(b64)
|
||||
channelSet = apponly_pb2.ChannelSet()
|
||||
channelSet.ParseFromString(decodedURL)
|
||||
|
||||
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
|
||||
self.writeChannel(ch.index)
|
||||
i = i + 1
|
||||
|
||||
def _requestSettings(self):
|
||||
"""
|
||||
Done with initial config messages, now send regular MeshPackets to ask for settings
|
||||
"""
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.get_radio_request = True
|
||||
|
||||
def onResponse(p):
|
||||
"""A closure to handle the response packet"""
|
||||
self.radioConfig = p["decoded"]["admin"]["raw"].get_radio_response
|
||||
|
||||
return self._sendAdmin(p,
|
||||
wantResponse=True,
|
||||
onResponse=onResponse)
|
||||
|
||||
def _requestChannel(self, channelNum: int):
|
||||
"""
|
||||
Done with initial config messages, now send regular MeshPackets to ask for settings
|
||||
"""
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.get_channel_request = channelNum + 1
|
||||
logging.debug(f"Requesting channel {channelNum}")
|
||||
|
||||
def onResponse(p):
|
||||
"""A closure to handle the response packet"""
|
||||
c = p["decoded"]["admin"]["raw"].get_channel_response
|
||||
self.partialChannels.append(c)
|
||||
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 >= self.iface.myInfo.max_channels - 1:
|
||||
self.channels = self.partialChannels
|
||||
# FIXME, the following should only be called after we have settings and channels
|
||||
self.iface._connected() # Tell everone else we are ready to go
|
||||
else:
|
||||
self._requestChannel(index + 1)
|
||||
|
||||
return self._sendAdmin(p,
|
||||
wantResponse=True,
|
||||
onResponse=onResponse)
|
||||
|
||||
def _sendAdmin(self, p: admin_pb2.AdminMessage, wantResponse=False,
|
||||
onResponse=None):
|
||||
"""Send an admin message to the specified node (or the local node if destNodeNum is zero)"""
|
||||
|
||||
return self.iface.sendData(p, self.nodeNum,
|
||||
portNum=portnums_pb2.PortNum.ADMIN_APP,
|
||||
wantAck=True,
|
||||
wantResponse=wantResponse,
|
||||
onResponse=onResponse)
|
||||
|
||||
|
||||
class MeshInterface:
|
||||
"""Interface class for meshtastic devices
|
||||
|
||||
@@ -130,6 +322,7 @@ class MeshInterface:
|
||||
self.nodes = None # FIXME
|
||||
self.isConnected = threading.Event()
|
||||
self.noProto = noProto
|
||||
self.localNode = Node(self, -1) # We fixup nodenum later
|
||||
self.myInfo = None # We don't have device info yet
|
||||
self.responseHandlers = {} # A map from request ID to the handler
|
||||
self.failure = None # If we've encountered a fatal exception it will be kept here
|
||||
@@ -148,6 +341,14 @@ class MeshInterface:
|
||||
logging.error(f'Traceback: {traceback}')
|
||||
self.close()
|
||||
|
||||
def showInfo(self):
|
||||
"""Show human readable summary about this object"""
|
||||
print(self.myInfo)
|
||||
self.localNode.showInfo()
|
||||
print("Nodes in mesh:")
|
||||
for n in self.nodes.values():
|
||||
print(stripnl(n))
|
||||
|
||||
def sendText(self, text: AnyStr,
|
||||
destinationId=BROADCAST_ADDR,
|
||||
wantAck=False,
|
||||
@@ -198,7 +399,7 @@ class MeshInterface:
|
||||
if len(data) > mesh_pb2.Constants.DATA_PAYLOAD_LEN:
|
||||
raise Exception("Data payload too big")
|
||||
|
||||
if portNum == portnums_pb2.PortNum.UNKNOWN_APP: # we are now more strict wrt port numbers
|
||||
if portNum == portnums_pb2.PortNum.UNKNOWN_APP: # we are now more strict wrt port numbers
|
||||
raise Exception("A non-zero port number must be specified")
|
||||
|
||||
meshPacket = mesh_pb2.MeshPacket()
|
||||
@@ -206,7 +407,8 @@ class MeshInterface:
|
||||
meshPacket.decoded.portnum = portNum
|
||||
meshPacket.decoded.want_response = wantResponse
|
||||
|
||||
p = self._sendPacket(meshPacket, destinationId, wantAck=wantAck, hopLimit=hopLimit)
|
||||
p = self._sendPacket(meshPacket, destinationId,
|
||||
wantAck=wantAck, hopLimit=hopLimit)
|
||||
if onResponse is not None:
|
||||
self._addResponseHandler(p.id, onResponse)
|
||||
return p
|
||||
@@ -283,43 +485,9 @@ class MeshInterface:
|
||||
self._sendToRadio(toRadio)
|
||||
return meshPacket
|
||||
|
||||
def waitForConfig(self, sleep=.1, maxsecs=20, attrs=('myInfo', 'nodes', 'radioConfig', 'channels')):
|
||||
def waitForConfig(self):
|
||||
"""Block until radio config is received. Returns True if config has been received."""
|
||||
for _ in range(int(maxsecs/sleep)):
|
||||
if all(map(lambda a: getattr(self, a, None), attrs)):
|
||||
return True
|
||||
time.sleep(sleep)
|
||||
return False
|
||||
|
||||
def _sendAdmin(self, p: admin_pb2.AdminMessage, destNodeNum = 0):
|
||||
"""Send an admin message to the specified node (or the local node if destNodeNum is zero)"""
|
||||
|
||||
if destNodeNum == 0:
|
||||
destNodeNum = self.myInfo.my_node_num
|
||||
|
||||
return self.sendData(p, destNodeNum,
|
||||
portNum=portnums_pb2.PortNum.ADMIN_APP,
|
||||
wantAck=True)
|
||||
|
||||
def writeConfig(self):
|
||||
"""Write the current (edited) radioConfig to the device"""
|
||||
if self.radioConfig == None:
|
||||
raise Exception("No RadioConfig has been read")
|
||||
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_radio.CopyFrom(self.radioConfig)
|
||||
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote config")
|
||||
|
||||
def writeChannel(self, channelIndex):
|
||||
"""Write the current (edited) channel to the device"""
|
||||
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.set_channel.CopyFrom(self.channels[channelIndex])
|
||||
|
||||
self._sendAdmin(p)
|
||||
logging.debug("Wrote channel {channelIndex}")
|
||||
return self.localNode.waitForConfig() and waitForSet(self, attrs=('myInfo', 'nodes'))
|
||||
|
||||
def getMyNodeInfo(self):
|
||||
if self.myInfo is None:
|
||||
@@ -344,80 +512,6 @@ class MeshInterface:
|
||||
return user.get('shortName', None)
|
||||
return None
|
||||
|
||||
def setOwner(self, long_name, short_name=None):
|
||||
"""Set device owner name"""
|
||||
nChars = 3
|
||||
minChars = 2
|
||||
if long_name is not None:
|
||||
long_name = long_name.strip()
|
||||
if short_name is None:
|
||||
words = long_name.split()
|
||||
if len(long_name) <= nChars:
|
||||
short_name = long_name
|
||||
elif len(words) >= minChars:
|
||||
short_name = ''.join(map(lambda word: word[0], words))
|
||||
else:
|
||||
trans = str.maketrans(dict.fromkeys('aeiouAEIOU'))
|
||||
short_name = long_name[0] + long_name[1:].translate(trans)
|
||||
if len(short_name) < nChars:
|
||||
short_name = long_name[:nChars]
|
||||
|
||||
p = admin_pb2.AdminMessage()
|
||||
|
||||
if long_name is not None:
|
||||
p.set_owner.long_name = long_name
|
||||
if short_name is not None:
|
||||
short_name = short_name.strip()
|
||||
if len(short_name) > nChars:
|
||||
short_name = short_name[:nChars]
|
||||
p.set_owner.short_name = short_name
|
||||
|
||||
return self._sendAdmin(p)
|
||||
|
||||
@property
|
||||
def channelURL(self):
|
||||
"""The sharable URL that describes the current channel
|
||||
"""
|
||||
# Only keep the primary/secondary channels, assume primary is first
|
||||
channelSet = apponly_pb2.ChannelSet()
|
||||
for c in self.channels:
|
||||
if c.role != channel_pb2.Channel.Role.DISABLED:
|
||||
channelSet.settings.append(c.settings)
|
||||
bytes = channelSet.SerializeToString()
|
||||
s = base64.urlsafe_b64encode(bytes).decode('ascii')
|
||||
return f"https://www.meshtastic.org/d/#{s}".replace("=", "")
|
||||
|
||||
def setURL(self, url):
|
||||
"""Set mesh network URL"""
|
||||
if self.radioConfig == None:
|
||||
raise Exception("No RadioConfig has been read")
|
||||
|
||||
# URLs are of the form https://www.meshtastic.org/d/#{base64_channel_set}
|
||||
# Split on '/#' to find the base64 encoded channel settings
|
||||
splitURL = url.split("/#")
|
||||
b64 = splitURL[-1]
|
||||
|
||||
# We normally strip padding to make for a shorter URL, but the python parser doesn't like
|
||||
# that. So add back any missing padding
|
||||
# per https://stackoverflow.com/a/9807138
|
||||
missing_padding = len(b64) % 4
|
||||
if missing_padding:
|
||||
b64 += '='* (4 - missing_padding)
|
||||
|
||||
decodedURL = base64.urlsafe_b64decode(b64)
|
||||
channelSet = apponly_pb2.ChannelSet()
|
||||
channelSet.ParseFromString(decodedURL)
|
||||
|
||||
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
|
||||
self.writeChannel(ch.index)
|
||||
i = i + 1
|
||||
|
||||
def _waitConnected(self):
|
||||
"""Block until the initial node db download is complete, or timeout
|
||||
and raise an exception"""
|
||||
@@ -445,18 +539,19 @@ class MeshInterface:
|
||||
def _connected(self):
|
||||
"""Called by this class to tell clients we are now fully connected to a node
|
||||
"""
|
||||
self.isConnected.set()
|
||||
catchAndIgnore("connection publish", lambda: pub.sendMessage(
|
||||
"meshtastic.connection.established", interface=self))
|
||||
# (because I'm lazy) _connected might be called when remote Node
|
||||
# objects complete their config reads, don't generate redundant isConnected
|
||||
# for the local interface
|
||||
if not self.isConnected.is_set():
|
||||
self.isConnected.set()
|
||||
catchAndIgnore("connection publish", lambda: pub.sendMessage(
|
||||
"meshtastic.connection.established", interface=self))
|
||||
|
||||
def _startConfig(self):
|
||||
"""Start device packets flowing"""
|
||||
self.myInfo = None
|
||||
self.nodes = {} # nodes keyed by ID
|
||||
self.nodesByNum = {} # nodes keyed by nodenum
|
||||
self.radioConfig = None
|
||||
self.channels = None
|
||||
self.partialChannels = [] # We keep our channels in a temp array until finished
|
||||
|
||||
startConfig = mesh_pb2.ToRadio()
|
||||
startConfig.want_config_id = MY_CONFIG_ID # we don't use this value
|
||||
@@ -479,59 +574,7 @@ class MeshInterface:
|
||||
"""
|
||||
Done with initial config messages, now send regular MeshPackets to ask for settings and channels
|
||||
"""
|
||||
self._requestSettings()
|
||||
self._requestChannel(0)
|
||||
|
||||
def _requestSettings(self):
|
||||
"""
|
||||
Done with initial config messages, now send regular MeshPackets to ask for settings
|
||||
"""
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.get_radio_request = True
|
||||
|
||||
def onResponse(p):
|
||||
"""A closure to handle the response packet"""
|
||||
self.radioConfig = p["decoded"]["admin"]["raw"].get_radio_response
|
||||
|
||||
return self.sendData(p, self.myInfo.my_node_num,
|
||||
portNum=portnums_pb2.PortNum.ADMIN_APP,
|
||||
wantAck=True,
|
||||
wantResponse=True,
|
||||
onResponse=onResponse)
|
||||
|
||||
def _requestChannel(self, channelNum: int):
|
||||
"""
|
||||
Done with initial config messages, now send regular MeshPackets to ask for settings
|
||||
"""
|
||||
p = admin_pb2.AdminMessage()
|
||||
p.get_channel_request = channelNum + 1
|
||||
logging.debug(f"Requesting channel {channelNum}")
|
||||
|
||||
def onResponse(p):
|
||||
"""A closure to handle the response packet"""
|
||||
c = p["decoded"]["admin"]["raw"].get_channel_response
|
||||
self.partialChannels.append(c)
|
||||
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 >= self.myInfo.max_channels - 1:
|
||||
self.channels = self.partialChannels
|
||||
# FIXME, the following should only be called after we have settings and channels
|
||||
self._connected() # Tell everone else we are ready to go
|
||||
else:
|
||||
self._requestChannel(index + 1)
|
||||
|
||||
return self.sendData(p, self.myInfo.my_node_num,
|
||||
portNum=portnums_pb2.PortNum.ADMIN_APP,
|
||||
wantAck=True,
|
||||
wantResponse=True,
|
||||
onResponse=onResponse)
|
||||
self.localNode.requestConfig()
|
||||
|
||||
def _handleFromRadio(self, fromRadioBytes):
|
||||
"""
|
||||
@@ -543,6 +586,7 @@ class MeshInterface:
|
||||
asDict = google.protobuf.json_format.MessageToDict(fromRadio)
|
||||
if fromRadio.HasField("my_info"):
|
||||
self.myInfo = fromRadio.my_info
|
||||
self.localNode.nodeNum = self.myInfo.my_node_num
|
||||
logging.debug(f"Received myinfo: {stripnl(fromRadio.my_info)}")
|
||||
|
||||
failmsg = None
|
||||
@@ -647,7 +691,8 @@ class MeshInterface:
|
||||
# from might be missing if the nodenum was zero.
|
||||
if not "from" in asDict:
|
||||
asDict["from"] = 0
|
||||
logging.error(f"Device returned a packet we sent, ignoring: {stripnl(asDict)}")
|
||||
logging.error(
|
||||
f"Device returned a packet we sent, ignoring: {stripnl(asDict)}")
|
||||
return
|
||||
if not "to" in asDict:
|
||||
asDict["to"] = 0
|
||||
|
||||
@@ -17,7 +17,6 @@ import pkg_resources
|
||||
from datetime import datetime
|
||||
import timeago
|
||||
from easy_table import EasyTable
|
||||
from google.protobuf.json_format import MessageToJson
|
||||
|
||||
"""We only import the tunnel code if we are on a platform that can run it"""
|
||||
have_tunnel = platform.system() == 'Linux'
|
||||
@@ -74,7 +73,7 @@ def fromStr(valstr):
|
||||
Args:
|
||||
valstr (string): A user provided string
|
||||
"""
|
||||
if(len(valstr) == 0): # Treat an emptystring as an empty bytes
|
||||
if(len(valstr) == 0): # Treat an emptystring as an empty bytes
|
||||
val = bytes()
|
||||
elif(valstr.startswith('0x')):
|
||||
# if needed convert to string with asBytes.decode('utf-8')
|
||||
@@ -110,13 +109,17 @@ def formatFloat(value, formatStr="{:.2f}", unit="", default="N/A"):
|
||||
def getLH(ts, default="N/A"):
|
||||
return datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') if ts else default
|
||||
|
||||
#Returns time ago for the last heard
|
||||
# Returns time ago for the last heard
|
||||
|
||||
|
||||
def getTimeAgo(ts, default="N/A"):
|
||||
return timeago.format(datetime.fromtimestamp(ts), datetime.now()) if ts else default
|
||||
|
||||
#Print Nodes
|
||||
# Print Nodes
|
||||
|
||||
|
||||
def printNodes(nodes, myId):
|
||||
#Create the table and define the structure
|
||||
# Create the table and define the structure
|
||||
table = EasyTable("Nodes")
|
||||
table.setCorners("/", "\\", "\\", "/")
|
||||
table.setOuterStructure("|", "-")
|
||||
@@ -126,22 +129,22 @@ def printNodes(nodes, myId):
|
||||
for node in nodes:
|
||||
if node['user']['id'] == myId:
|
||||
continue
|
||||
#aux var to get not defined keys
|
||||
lat=formatFloat(node['position'].get("latitude"), "{:.4f}", "°")
|
||||
lon=formatFloat(node['position'].get("longitude"), "{:.4f}", "°")
|
||||
alt=formatFloat(node['position'].get("altitude"), "{:.0f}", " m")
|
||||
batt=formatFloat(node['position'].get("batteryLevel"), "{:.2f}", "%")
|
||||
snr=formatFloat(node.get("snr"), "{:.2f}", " dB")
|
||||
LH= getLH(node['position'].get("time"))
|
||||
# aux var to get not defined keys
|
||||
lat = formatFloat(node['position'].get("latitude"), "{:.4f}", "°")
|
||||
lon = formatFloat(node['position'].get("longitude"), "{:.4f}", "°")
|
||||
alt = formatFloat(node['position'].get("altitude"), "{:.0f}", " m")
|
||||
batt = formatFloat(node['position'].get("batteryLevel"), "{:.2f}", "%")
|
||||
snr = formatFloat(node.get("snr"), "{:.2f}", " dB")
|
||||
LH = getLH(node['position'].get("time"))
|
||||
timeAgo = getTimeAgo(node['position'].get("time"))
|
||||
tableData.append({"N":0, "User":node['user']['longName'],
|
||||
"AKA":node['user']['shortName'], "ID":node['user']['id'],
|
||||
"Position":lat+", "+lon+", "+alt,
|
||||
"Battery":batt, "SNR":snr,
|
||||
"LastHeard":LH, "Since":timeAgo})
|
||||
|
||||
Rows = sorted(tableData, key=lambda k: k['LastHeard'], reverse=True)
|
||||
RowsOk = sorted(Rows, key=lambda k:k ['LastHeard'].startswith("N/A"))
|
||||
tableData.append({"N": 0, "User": node['user']['longName'],
|
||||
"AKA": node['user']['shortName'], "ID": node['user']['id'],
|
||||
"Position": lat+", "+lon+", "+alt,
|
||||
"Battery": batt, "SNR": snr,
|
||||
"LastHeard": LH, "Since": timeAgo})
|
||||
|
||||
Rows = sorted(tableData, key=lambda k: k['LastHeard'], reverse=True)
|
||||
RowsOk = sorted(Rows, key=lambda k: k['LastHeard'].startswith("N/A"))
|
||||
for i in range(len(RowsOk)):
|
||||
RowsOk[i]['N'] = i+1
|
||||
table.setData(RowsOk)
|
||||
@@ -171,7 +174,7 @@ def onConnected(interface):
|
||||
try:
|
||||
global args
|
||||
print("Connected to radio")
|
||||
prefs = interface.radioConfig.preferences
|
||||
prefs = interface.localNode.radioConfig.preferences
|
||||
|
||||
if args.settime or args.setlat or args.setlon or args.setalt:
|
||||
closeNow = True
|
||||
@@ -254,14 +257,13 @@ def onConnected(interface):
|
||||
|
||||
if args.seturl:
|
||||
closeNow = True
|
||||
interface.setURL(args.seturl)
|
||||
interface.localNode.setURL(args.seturl)
|
||||
|
||||
# handle changing channels
|
||||
if args.setchan or args.setch_longslow or args.setch_shortfast \
|
||||
or args.seturl != None:
|
||||
if args.setchan or args.setch_longslow or args.setch_shortfast:
|
||||
closeNow = True
|
||||
|
||||
ch = interface.channels[channelIndex]
|
||||
ch = interface.localNode.channels[channelIndex]
|
||||
|
||||
def setSimpleChannel(modem_config):
|
||||
"""Set one of the simple modem_config only based channels"""
|
||||
@@ -287,25 +289,16 @@ def onConnected(interface):
|
||||
setPref(ch.settings, pref[0], pref[1])
|
||||
|
||||
print("Writing modified channels to device")
|
||||
interface.writeChannel(channelIndex)
|
||||
interface.localNode.writeChannel(channelIndex)
|
||||
|
||||
if args.info:
|
||||
closeNow = True
|
||||
print(interface.myInfo)
|
||||
print(interface.radioConfig)
|
||||
print("Channels:")
|
||||
for c in interface.channels:
|
||||
if c.role != channel_pb2.Channel.Role.DISABLED:
|
||||
cStr = MessageToJson(c.settings).replace("\n", "")
|
||||
print(f" {channel_pb2.Channel.Role.Name(c.role)} {cStr}")
|
||||
print(f"\nChannel URL {interface.channelURL}")
|
||||
print("Nodes in mesh:")
|
||||
for n in interface.nodes.values():
|
||||
print(stripnl(n))
|
||||
interface.showInfo()
|
||||
|
||||
if args.nodes:
|
||||
closeNow = True
|
||||
printNodes(interface.nodes.values(), interface.getMyNodeInfo()['user']['id'])
|
||||
printNodes(interface.nodes.values(),
|
||||
interface.getMyNodeInfo()['user']['id'])
|
||||
|
||||
if args.qr:
|
||||
closeNow = True
|
||||
@@ -345,7 +338,7 @@ def common():
|
||||
global args
|
||||
logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO)
|
||||
|
||||
if len(sys.argv)==1:
|
||||
if len(sys.argv) == 1:
|
||||
parser.print_help(sys.stderr)
|
||||
sys.exit(1)
|
||||
else:
|
||||
@@ -377,7 +370,8 @@ def common():
|
||||
logfile = None
|
||||
else:
|
||||
logging.info(f"Logging serial output to {args.seriallog}")
|
||||
logfile = open(args.seriallog, 'w+', buffering=1) # line buffering
|
||||
logfile = open(args.seriallog, 'w+',
|
||||
buffering=1) # line buffering
|
||||
|
||||
subscribe()
|
||||
if args.ble:
|
||||
@@ -389,7 +383,8 @@ def common():
|
||||
client = SerialInterface(
|
||||
args.port, debugOut=logfile, noProto=args.noproto)
|
||||
|
||||
sys.exit(0)
|
||||
# don't call exit, background threads might be running still
|
||||
# sys.exit(0)
|
||||
|
||||
|
||||
def initParser():
|
||||
|
||||
@@ -19,7 +19,7 @@ DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
syntax='proto3',
|
||||
serialized_options=b'\n\023com.geeksville.meshB\rChannelProtosH\003',
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=b'\n\rchannel.proto\"\xe6\x02\n\x0f\x43hannelSettings\x12\x10\n\x08tx_power\x18\x01 \x01(\x05\x12\x32\n\x0cmodem_config\x18\x03 \x01(\x0e\x32\x1c.ChannelSettings.ModemConfig\x12\x11\n\tbandwidth\x18\x06 \x01(\r\x12\x15\n\rspread_factor\x18\x07 \x01(\r\x12\x13\n\x0b\x63oding_rate\x18\x08 \x01(\r\x12\x13\n\x0b\x63hannel_num\x18\t \x01(\r\x12\x0b\n\x03psk\x18\x04 \x01(\x0c\x12\x0c\n\x04name\x18\x05 \x01(\t\x12\n\n\x02id\x18\n \x01(\x07\x12\x16\n\x0euplink_enabled\x18\x10 \x01(\x08\x12\x18\n\x10\x64ownlink_enabled\x18\x11 \x01(\x08\"`\n\x0bModemConfig\x12\x12\n\x0e\x42w125Cr45Sf128\x10\x00\x12\x12\n\x0e\x42w500Cr45Sf128\x10\x01\x12\x14\n\x10\x42w31_25Cr48Sf512\x10\x02\x12\x13\n\x0f\x42w125Cr48Sf4096\x10\x03\"\x8b\x01\n\x07\x43hannel\x12\r\n\x05index\x18\x01 \x01(\r\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&\n\x13\x63om.geeksville.meshB\rChannelProtosH\x03\x62\x06proto3'
|
||||
serialized_pb=b'\n\rchannel.proto\"\xe6\x02\n\x0f\x43hannelSettings\x12\x10\n\x08tx_power\x18\x01 \x01(\x05\x12\x32\n\x0cmodem_config\x18\x03 \x01(\x0e\x32\x1c.ChannelSettings.ModemConfig\x12\x11\n\tbandwidth\x18\x06 \x01(\r\x12\x15\n\rspread_factor\x18\x07 \x01(\r\x12\x13\n\x0b\x63oding_rate\x18\x08 \x01(\r\x12\x13\n\x0b\x63hannel_num\x18\t \x01(\r\x12\x0b\n\x03psk\x18\x04 \x01(\x0c\x12\x0c\n\x04name\x18\x05 \x01(\t\x12\n\n\x02id\x18\n \x01(\x07\x12\x16\n\x0euplink_enabled\x18\x10 \x01(\x08\x12\x18\n\x10\x64ownlink_enabled\x18\x11 \x01(\x08\"`\n\x0bModemConfig\x12\x12\n\x0e\x42w125Cr45Sf128\x10\x00\x12\x12\n\x0e\x42w500Cr45Sf128\x10\x01\x12\x14\n\x10\x42w31_25Cr48Sf512\x10\x02\x12\x13\n\x0f\x42w125Cr48Sf4096\x10\x03\"\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&\n\x13\x63om.geeksville.meshB\rChannelProtosH\x03\x62\x06proto3'
|
||||
)
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ _CHANNEL = _descriptor.Descriptor(
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='index', full_name='Channel.index', index=0,
|
||||
number=1, type=13, cpp_type=3, label=1,
|
||||
number=1, type=5, cpp_type=1, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
|
||||
@@ -21,7 +21,7 @@ DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
syntax='proto3',
|
||||
serialized_options=b'\n\023com.geeksville.meshB\nMeshProtosH\003',
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=b'\n\nmesh.proto\x1a\x0eportnums.proto\"v\n\x08Position\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\x15\n\rbattery_level\x18\x04 \x01(\x05\x12\x0c\n\x04time\x18\t \x01(\x07J\x04\x08\x07\x10\x08J\x04\x08\x08\x10\t\"J\n\x04User\x12\n\n\x02id\x18\x01 \x01(\t\x12\x11\n\tlong_name\x18\x02 \x01(\t\x12\x12\n\nshort_name\x18\x03 \x01(\t\x12\x0f\n\x07macaddr\x18\x04 \x01(\x0c\"\x1f\n\x0eRouteDiscovery\x12\r\n\x05route\x18\x02 \x03(\x07\"\x8e\x02\n\x07Routing\x12(\n\rroute_request\x18\x01 \x01(\x0b\x32\x0f.RouteDiscoveryH\x00\x12&\n\x0broute_reply\x18\x02 \x01(\x0b\x32\x0f.RouteDiscoveryH\x00\x12&\n\x0c\x65rror_reason\x18\x03 \x01(\x0e\x32\x0e.Routing.ErrorH\x00\"~\n\x05\x45rror\x12\x08\n\x04NONE\x10\x00\x12\x0c\n\x08NO_ROUTE\x10\x01\x12\x0b\n\x07GOT_NAK\x10\x02\x12\x0b\n\x07TIMEOUT\x10\x03\x12\x10\n\x0cNO_INTERFACE\x10\x04\x12\x12\n\x0eMAX_RETRANSMIT\x10\x05\x12\x0e\n\nNO_CHANNEL\x10\x06\x12\r\n\tTOO_LARGE\x10\x07\x42\t\n\x07variant\"{\n\x04\x44\x61ta\x12\x19\n\x07portnum\x18\x01 \x01(\x0e\x32\x08.PortNum\x12\x0f\n\x07payload\x18\x02 \x01(\x0c\x12\x15\n\rwant_response\x18\x03 \x01(\x08\x12\x0c\n\x04\x64\x65st\x18\x04 \x01(\x07\x12\x0e\n\x06source\x18\x05 \x01(\x07\x12\x12\n\nrequest_id\x18\x06 \x01(\x07\"\xcf\x02\n\nMeshPacket\x12\x0c\n\x04\x66rom\x18\x01 \x01(\x07\x12\n\n\x02to\x18\x02 \x01(\x07\x12\x0f\n\x07\x63hannel\x18\x03 \x01(\r\x12\x18\n\x07\x64\x65\x63oded\x18\x04 \x01(\x0b\x32\x05.DataH\x00\x12\x13\n\tencrypted\x18\x05 \x01(\x0cH\x00\x12\n\n\x02id\x18\x06 \x01(\x07\x12\x0f\n\x07rx_time\x18\x07 \x01(\x07\x12\x0e\n\x06rx_snr\x18\x08 \x01(\x02\x12\x11\n\thop_limit\x18\n \x01(\r\x12\x10\n\x08want_ack\x18\x0b \x01(\x08\x12&\n\x08priority\x18\x0c \x01(\x0e\x32\x14.MeshPacket.Priority\"[\n\x08Priority\x12\t\n\x05UNSET\x10\x00\x12\x07\n\x03MIN\x10\x01\x12\x0e\n\nBACKGROUND\x10\n\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10@\x12\x0c\n\x08RELIABLE\x10\x46\x12\x07\n\x03\x41\x43K\x10x\x12\x07\n\x03MAX\x10\x7f\x42\x10\n\x0epayloadVariant\"h\n\x08NodeInfo\x12\x0b\n\x03num\x18\x01 \x01(\r\x12\x13\n\x04user\x18\x02 \x01(\x0b\x32\x05.User\x12\x1b\n\x08position\x18\x03 \x01(\x0b\x32\t.Position\x12\x0b\n\x03snr\x18\x07 \x01(\x02\x12\x10\n\x08next_hop\x18\x05 \x01(\r\"\xa6\x02\n\nMyNodeInfo\x12\x13\n\x0bmy_node_num\x18\x01 \x01(\r\x12\x0f\n\x07has_gps\x18\x02 \x01(\x08\x12\x11\n\tnum_bands\x18\x03 \x01(\r\x12\x14\n\x0cmax_channels\x18\x0f \x01(\r\x12\x12\n\x06region\x18\x04 \x01(\tB\x02\x18\x01\x12\x10\n\x08hw_model\x18\x05 \x01(\t\x12\x18\n\x10\x66irmware_version\x18\x06 \x01(\t\x12&\n\nerror_code\x18\x07 \x01(\x0e\x32\x12.CriticalErrorCode\x12\x15\n\rerror_address\x18\x08 \x01(\r\x12\x13\n\x0b\x65rror_count\x18\t \x01(\r\x12\x1c\n\x14message_timeout_msec\x18\r \x01(\r\x12\x17\n\x0fmin_app_version\x18\x0e \x01(\r\"\xb5\x01\n\tLogRecord\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x0c\n\x04time\x18\x02 \x01(\x07\x12\x0e\n\x06source\x18\x03 \x01(\t\x12\x1f\n\x05level\x18\x04 \x01(\x0e\x32\x10.LogRecord.Level\"X\n\x05Level\x12\t\n\x05UNSET\x10\x00\x12\x0c\n\x08\x43RITICAL\x10\x32\x12\t\n\x05\x45RROR\x10(\x12\x0b\n\x07WARNING\x10\x1e\x12\x08\n\x04INFO\x10\x14\x12\t\n\x05\x44\x45\x42UG\x10\n\x12\t\n\x05TRACE\x10\x05\"\xe9\x01\n\tFromRadio\x12\x0b\n\x03num\x18\x01 \x01(\r\x12\x1d\n\x06packet\x18\x0b \x01(\x0b\x32\x0b.MeshPacketH\x00\x12\x1e\n\x07my_info\x18\x03 \x01(\x0b\x32\x0b.MyNodeInfoH\x00\x12\x1e\n\tnode_info\x18\x04 \x01(\x0b\x32\t.NodeInfoH\x00\x12 \n\nlog_record\x18\x07 \x01(\x0b\x32\n.LogRecordH\x00\x12\x1c\n\x12\x63onfig_complete_id\x18\x08 \x01(\rH\x00\x12\x12\n\x08rebooted\x18\t \x01(\x08H\x00\x42\x10\n\x0epayloadVariantJ\x04\x08\x02\x10\x03J\x04\x08\x06\x10\x07\"l\n\x07ToRadio\x12\x1d\n\x06packet\x18\x02 \x01(\x0b\x32\x0b.MeshPacketH\x00\x12\x18\n\x0ewant_config_id\x18\x64 \x01(\rH\x00\x42\x10\n\x0epayloadVariantJ\x04\x08\x01\x10\x02J\x04\x08\x65\x10\x66J\x04\x08\x66\x10gJ\x04\x08g\x10h*.\n\tConstants\x12\n\n\x06Unused\x10\x00\x12\x15\n\x10\x44\x41TA_PAYLOAD_LEN\x10\xf0\x01*\xaf\x01\n\x11\x43riticalErrorCode\x12\x08\n\x04None\x10\x00\x12\x0e\n\nTxWatchdog\x10\x01\x12\x12\n\x0eSleepEnterWait\x10\x02\x12\x0b\n\x07NoRadio\x10\x03\x12\x0f\n\x0bUnspecified\x10\x04\x12\x13\n\x0fUBloxInitFailed\x10\x05\x12\x0c\n\x08NoAXP192\x10\x06\x12\x17\n\x13InvalidRadioSetting\x10\x07\x12\x12\n\x0eTransmitFailed\x10\x08\x42#\n\x13\x63om.geeksville.meshB\nMeshProtosH\x03\x62\x06proto3'
|
||||
serialized_pb=b'\n\nmesh.proto\x1a\x0eportnums.proto\"v\n\x08Position\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\x15\n\rbattery_level\x18\x04 \x01(\x05\x12\x0c\n\x04time\x18\t \x01(\x07J\x04\x08\x07\x10\x08J\x04\x08\x08\x10\t\"J\n\x04User\x12\n\n\x02id\x18\x01 \x01(\t\x12\x11\n\tlong_name\x18\x02 \x01(\t\x12\x12\n\nshort_name\x18\x03 \x01(\t\x12\x0f\n\x07macaddr\x18\x04 \x01(\x0c\"\x1f\n\x0eRouteDiscovery\x12\r\n\x05route\x18\x02 \x03(\x07\"\x8e\x02\n\x07Routing\x12(\n\rroute_request\x18\x01 \x01(\x0b\x32\x0f.RouteDiscoveryH\x00\x12&\n\x0broute_reply\x18\x02 \x01(\x0b\x32\x0f.RouteDiscoveryH\x00\x12&\n\x0c\x65rror_reason\x18\x03 \x01(\x0e\x32\x0e.Routing.ErrorH\x00\"~\n\x05\x45rror\x12\x08\n\x04NONE\x10\x00\x12\x0c\n\x08NO_ROUTE\x10\x01\x12\x0b\n\x07GOT_NAK\x10\x02\x12\x0b\n\x07TIMEOUT\x10\x03\x12\x10\n\x0cNO_INTERFACE\x10\x04\x12\x12\n\x0eMAX_RETRANSMIT\x10\x05\x12\x0e\n\nNO_CHANNEL\x10\x06\x12\r\n\tTOO_LARGE\x10\x07\x42\t\n\x07variant\"{\n\x04\x44\x61ta\x12\x19\n\x07portnum\x18\x01 \x01(\x0e\x32\x08.PortNum\x12\x0f\n\x07payload\x18\x02 \x01(\x0c\x12\x15\n\rwant_response\x18\x03 \x01(\x08\x12\x0c\n\x04\x64\x65st\x18\x04 \x01(\x07\x12\x0e\n\x06source\x18\x05 \x01(\x07\x12\x12\n\nrequest_id\x18\x06 \x01(\x07\"\xcf\x02\n\nMeshPacket\x12\x0c\n\x04\x66rom\x18\x01 \x01(\x07\x12\n\n\x02to\x18\x02 \x01(\x07\x12\x0f\n\x07\x63hannel\x18\x03 \x01(\r\x12\x18\n\x07\x64\x65\x63oded\x18\x04 \x01(\x0b\x32\x05.DataH\x00\x12\x13\n\tencrypted\x18\x05 \x01(\x0cH\x00\x12\n\n\x02id\x18\x06 \x01(\x07\x12\x0f\n\x07rx_time\x18\x07 \x01(\x07\x12\x0e\n\x06rx_snr\x18\x08 \x01(\x02\x12\x11\n\thop_limit\x18\n \x01(\r\x12\x10\n\x08want_ack\x18\x0b \x01(\x08\x12&\n\x08priority\x18\x0c \x01(\x0e\x32\x14.MeshPacket.Priority\"[\n\x08Priority\x12\t\n\x05UNSET\x10\x00\x12\x07\n\x03MIN\x10\x01\x12\x0e\n\nBACKGROUND\x10\n\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10@\x12\x0c\n\x08RELIABLE\x10\x46\x12\x07\n\x03\x41\x43K\x10x\x12\x07\n\x03MAX\x10\x7f\x42\x10\n\x0epayloadVariant\"h\n\x08NodeInfo\x12\x0b\n\x03num\x18\x01 \x01(\r\x12\x13\n\x04user\x18\x02 \x01(\x0b\x32\x05.User\x12\x1b\n\x08position\x18\x03 \x01(\x0b\x32\t.Position\x12\x0b\n\x03snr\x18\x07 \x01(\x02\x12\x10\n\x08next_hop\x18\x05 \x01(\r\"\xa6\x02\n\nMyNodeInfo\x12\x13\n\x0bmy_node_num\x18\x01 \x01(\r\x12\x0f\n\x07has_gps\x18\x02 \x01(\x08\x12\x11\n\tnum_bands\x18\x03 \x01(\r\x12\x14\n\x0cmax_channels\x18\x0f \x01(\r\x12\x12\n\x06region\x18\x04 \x01(\tB\x02\x18\x01\x12\x10\n\x08hw_model\x18\x05 \x01(\t\x12\x18\n\x10\x66irmware_version\x18\x06 \x01(\t\x12&\n\nerror_code\x18\x07 \x01(\x0e\x32\x12.CriticalErrorCode\x12\x15\n\rerror_address\x18\x08 \x01(\r\x12\x13\n\x0b\x65rror_count\x18\t \x01(\r\x12\x1c\n\x14message_timeout_msec\x18\r \x01(\r\x12\x17\n\x0fmin_app_version\x18\x0e \x01(\r\"\xb5\x01\n\tLogRecord\x12\x0f\n\x07message\x18\x01 \x01(\t\x12\x0c\n\x04time\x18\x02 \x01(\x07\x12\x0e\n\x06source\x18\x03 \x01(\t\x12\x1f\n\x05level\x18\x04 \x01(\x0e\x32\x10.LogRecord.Level\"X\n\x05Level\x12\t\n\x05UNSET\x10\x00\x12\x0c\n\x08\x43RITICAL\x10\x32\x12\t\n\x05\x45RROR\x10(\x12\x0b\n\x07WARNING\x10\x1e\x12\x08\n\x04INFO\x10\x14\x12\t\n\x05\x44\x45\x42UG\x10\n\x12\t\n\x05TRACE\x10\x05\"\xe9\x01\n\tFromRadio\x12\x0b\n\x03num\x18\x01 \x01(\r\x12\x1d\n\x06packet\x18\x0b \x01(\x0b\x32\x0b.MeshPacketH\x00\x12\x1e\n\x07my_info\x18\x03 \x01(\x0b\x32\x0b.MyNodeInfoH\x00\x12\x1e\n\tnode_info\x18\x04 \x01(\x0b\x32\t.NodeInfoH\x00\x12 \n\nlog_record\x18\x07 \x01(\x0b\x32\n.LogRecordH\x00\x12\x1c\n\x12\x63onfig_complete_id\x18\x08 \x01(\rH\x00\x12\x12\n\x08rebooted\x18\t \x01(\x08H\x00\x42\x10\n\x0epayloadVariantJ\x04\x08\x02\x10\x03J\x04\x08\x06\x10\x07\"l\n\x07ToRadio\x12\x1d\n\x06packet\x18\x02 \x01(\x0b\x32\x0b.MeshPacketH\x00\x12\x18\n\x0ewant_config_id\x18\x64 \x01(\rH\x00\x42\x10\n\x0epayloadVariantJ\x04\x08\x01\x10\x02J\x04\x08\x65\x10\x66J\x04\x08\x66\x10gJ\x04\x08g\x10h*.\n\tConstants\x12\n\n\x06Unused\x10\x00\x12\x15\n\x10\x44\x41TA_PAYLOAD_LEN\x10\xf0\x01*\xbd\x01\n\x11\x43riticalErrorCode\x12\x08\n\x04None\x10\x00\x12\x0e\n\nTxWatchdog\x10\x01\x12\x12\n\x0eSleepEnterWait\x10\x02\x12\x0b\n\x07NoRadio\x10\x03\x12\x0f\n\x0bUnspecified\x10\x04\x12\x13\n\x0fUBloxInitFailed\x10\x05\x12\x0c\n\x08NoAXP192\x10\x06\x12\x17\n\x13InvalidRadioSetting\x10\x07\x12\x12\n\x0eTransmitFailed\x10\x08\x12\x0c\n\x08\x42rownout\x10\tB#\n\x13\x63om.geeksville.meshB\nMeshProtosH\x03\x62\x06proto3'
|
||||
,
|
||||
dependencies=[portnums__pb2.DESCRIPTOR,])
|
||||
|
||||
@@ -103,11 +103,16 @@ _CRITICALERRORCODE = _descriptor.EnumDescriptor(
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='Brownout', index=9, number=9,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=1977,
|
||||
serialized_end=2152,
|
||||
serialized_end=2166,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_CRITICALERRORCODE)
|
||||
|
||||
@@ -123,6 +128,7 @@ UBloxInitFailed = 5
|
||||
NoAXP192 = 6
|
||||
InvalidRadioSetting = 7
|
||||
TransmitFailed = 8
|
||||
Brownout = 9
|
||||
|
||||
|
||||
_ROUTING_ERROR = _descriptor.EnumDescriptor(
|
||||
|
||||
2
proto
2
proto
Submodule proto updated: 7c025b9a4d...6dac3099be
Reference in New Issue
Block a user