From e99844abbd95852aaadfff6107865acee38472b6 Mon Sep 17 00:00:00 2001
From: Kevin Hester
Date: Fri, 16 Apr 2021 11:27:33 +0800
Subject: [PATCH] 1.2.29
---
docs/meshtastic/index.html | 207 +++++++++++++++++++++++++++++++---
docs/meshtastic/mesh_pb2.html | 112 ++++++++++++++----
docs/meshtastic/test.html | 40 ++++---
setup.py | 2 +-
4 files changed, 311 insertions(+), 50 deletions(-)
diff --git a/docs/meshtastic/index.html b/docs/meshtastic/index.html
index 7f233c7..e44ae16 100644
--- a/docs/meshtastic/index.html
+++ b/docs/meshtastic/index.html
@@ -154,11 +154,14 @@ import time
import base64
import platform
import socket
+import timeago
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, DeferredExecution, Timeout
from .node import Node
from pubsub import pub
from dotmap import DotMap
+from datetime import datetime
+from tabulate import tabulate
from typing import *
from google.protobuf.json_format import MessageToJson
@@ -247,12 +250,65 @@ class MeshInterface:
logging.error(f'Traceback: {traceback}')
self.close()
- def showInfo(self):
+ def showInfo(self, file=sys.stdout):
"""Show human readable summary about this object"""
- print(f"My info: {stripnl(MessageToJson(self.myInfo))}")
- print("\nNodes in mesh:")
+
+ print(f"Owner: {self.getLongName()} ({self.getShortName()})", file=file)
+ print(f"\nMy info: {stripnl(MessageToJson(self.myInfo))}", file=file)
+ print("\nNodes in mesh:", file=file)
for n in self.nodes.values():
- print(" " + stripnl(n))
+ print(f" {stripnl(n)}", file=file)
+
+ def showNodes(self, includeSelf=True, file=sys.stdout):
+ """Show table summary of nodes in mesh"""
+ def formatFloat(value, precision=2, unit=''):
+ return f'{value:.{precision}f}{unit}' if value else None
+
+ def getLH(ts):
+ return datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') if ts else None
+
+ def getTimeAgo(ts):
+ return timeago.format(datetime.fromtimestamp(ts), datetime.now()) if ts else None
+
+ rows = []
+ for node in self.nodes.values():
+ if not includeSelf and node['num'] == self.localNode.nodeNum:
+ continue
+
+ row = { "N": 0 }
+
+ user = node.get('user')
+ if user:
+ row.update({
+ "User": user['longName'],
+ "AKA": user['shortName'],
+ "ID": user['id'],
+ })
+
+ pos = node.get('position')
+ if pos:
+ row.update({
+ "Latitude": formatFloat(pos.get("latitude"), 4, "°"),
+ "Longitude": formatFloat(pos.get("longitude"), 4, "°"),
+ "Altitude": formatFloat(pos.get("altitude"), 0, " m"),
+ "Battery": formatFloat(pos.get("batteryLevel"), 2, "%"),
+ })
+
+ row.update({
+ "SNR": formatFloat(node.get("snr"), 2, " dB"),
+ "LastHeard": getLH( node.get("lastHeard")),
+ "Since": getTimeAgo( node.get("lastHeard")),
+ })
+
+ rows.append(row)
+
+ # Why doesn't this way work?
+ #rows.sort(key=lambda r: r.get('LastHeard', '0000'), reverse=True)
+ rows.sort(key=lambda r: r.get('LastHeard') or '0000', reverse=True)
+ for i, row in enumerate(rows):
+ row['N'] = i+1
+
+ print(tabulate(rows, headers='keys', missingval='N/A', tablefmt='fancy_grid'), file=file)
def getNode(self, nodeId):
"""Return a node object which contains device settings and channel info"""
@@ -771,7 +827,7 @@ class StreamInterface(MeshInterface):
self._wantExit = False
# FIXME, figure out why daemon=True causes reader thread to exit too early
- self._rxThread = threading.Thread(target=self.__reader, args=())
+ self._rxThread = threading.Thread(target=self.__reader, args=(), daemon=True)
MeshInterface.__init__(self, debugOut=debugOut, noProto=noProto)
@@ -1190,6 +1246,7 @@ noProto – If True, don't try to run our protocol on the link - just be a d
sendPosition
sendText
showInfo
+showNodes
waitForConfig
@@ -1295,12 +1352,65 @@ noProto – If True, don't try to run our protocol on the link - just be a d
logging.error(f'Traceback: {traceback}')
self.close()
- def showInfo(self):
+ def showInfo(self, file=sys.stdout):
"""Show human readable summary about this object"""
- print(f"My info: {stripnl(MessageToJson(self.myInfo))}")
- print("\nNodes in mesh:")
+
+ print(f"Owner: {self.getLongName()} ({self.getShortName()})", file=file)
+ print(f"\nMy info: {stripnl(MessageToJson(self.myInfo))}", file=file)
+ print("\nNodes in mesh:", file=file)
for n in self.nodes.values():
- print(" " + stripnl(n))
+ print(f" {stripnl(n)}", file=file)
+
+ def showNodes(self, includeSelf=True, file=sys.stdout):
+ """Show table summary of nodes in mesh"""
+ def formatFloat(value, precision=2, unit=''):
+ return f'{value:.{precision}f}{unit}' if value else None
+
+ def getLH(ts):
+ return datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') if ts else None
+
+ def getTimeAgo(ts):
+ return timeago.format(datetime.fromtimestamp(ts), datetime.now()) if ts else None
+
+ rows = []
+ for node in self.nodes.values():
+ if not includeSelf and node['num'] == self.localNode.nodeNum:
+ continue
+
+ row = { "N": 0 }
+
+ user = node.get('user')
+ if user:
+ row.update({
+ "User": user['longName'],
+ "AKA": user['shortName'],
+ "ID": user['id'],
+ })
+
+ pos = node.get('position')
+ if pos:
+ row.update({
+ "Latitude": formatFloat(pos.get("latitude"), 4, "°"),
+ "Longitude": formatFloat(pos.get("longitude"), 4, "°"),
+ "Altitude": formatFloat(pos.get("altitude"), 0, " m"),
+ "Battery": formatFloat(pos.get("batteryLevel"), 2, "%"),
+ })
+
+ row.update({
+ "SNR": formatFloat(node.get("snr"), 2, " dB"),
+ "LastHeard": getLH( node.get("lastHeard")),
+ "Since": getTimeAgo( node.get("lastHeard")),
+ })
+
+ rows.append(row)
+
+ # Why doesn't this way work?
+ #rows.sort(key=lambda r: r.get('LastHeard', '0000'), reverse=True)
+ rows.sort(key=lambda r: r.get('LastHeard') or '0000', reverse=True)
+ for i, row in enumerate(rows):
+ row['N'] = i+1
+
+ print(tabulate(rows, headers='keys', missingval='N/A', tablefmt='fancy_grid'), file=file)
def getNode(self, nodeId):
"""Return a node object which contains device settings and channel info"""
@@ -2003,7 +2113,7 @@ wantResponse – True if you want the service on the other side to send an a
-def showInfo(self)
+def showInfo(self, file=sys.stdout)
Show human readable summary about this object
@@ -2011,12 +2121,75 @@ wantResponse – True if you want the service on the other side to send an a
Expand source code
-def showInfo(self):
+def showInfo(self, file=sys.stdout):
"""Show human readable summary about this object"""
- print(f"My info: {stripnl(MessageToJson(self.myInfo))}")
- print("\nNodes in mesh:")
+
+ print(f"Owner: {self.getLongName()} ({self.getShortName()})", file=file)
+ print(f"\nMy info: {stripnl(MessageToJson(self.myInfo))}", file=file)
+ print("\nNodes in mesh:", file=file)
for n in self.nodes.values():
- print(" " + stripnl(n))
+ print(f" {stripnl(n)}", file=file)
+
+
+
+def showNodes(self, includeSelf=True, file=sys.stdout)
+
+
+Show table summary of nodes in mesh
+
+
+Expand source code
+
+def showNodes(self, includeSelf=True, file=sys.stdout):
+ """Show table summary of nodes in mesh"""
+ def formatFloat(value, precision=2, unit=''):
+ return f'{value:.{precision}f}{unit}' if value else None
+
+ def getLH(ts):
+ return datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') if ts else None
+
+ def getTimeAgo(ts):
+ return timeago.format(datetime.fromtimestamp(ts), datetime.now()) if ts else None
+
+ rows = []
+ for node in self.nodes.values():
+ if not includeSelf and node['num'] == self.localNode.nodeNum:
+ continue
+
+ row = { "N": 0 }
+
+ user = node.get('user')
+ if user:
+ row.update({
+ "User": user['longName'],
+ "AKA": user['shortName'],
+ "ID": user['id'],
+ })
+
+ pos = node.get('position')
+ if pos:
+ row.update({
+ "Latitude": formatFloat(pos.get("latitude"), 4, "°"),
+ "Longitude": formatFloat(pos.get("longitude"), 4, "°"),
+ "Altitude": formatFloat(pos.get("altitude"), 0, " m"),
+ "Battery": formatFloat(pos.get("batteryLevel"), 2, "%"),
+ })
+
+ row.update({
+ "SNR": formatFloat(node.get("snr"), 2, " dB"),
+ "LastHeard": getLH( node.get("lastHeard")),
+ "Since": getTimeAgo( node.get("lastHeard")),
+ })
+
+ rows.append(row)
+
+ # Why doesn't this way work?
+ #rows.sort(key=lambda r: r.get('LastHeard', '0000'), reverse=True)
+ rows.sort(key=lambda r: r.get('LastHeard') or '0000', reverse=True)
+ for i, row in enumerate(rows):
+ row['N'] = i+1
+
+ print(tabulate(rows, headers='keys', missingval='N/A', tablefmt='fancy_grid'), file=file)
@@ -2138,6 +2311,7 @@ debugOut {stream} – If a stream is provided, any debug serial output from
sendPosition
sendText
showInfo
+showNodes
waitForConfig
@@ -2186,7 +2360,7 @@ debugOut {stream} – If a stream is provided, any debug serial output from
self._wantExit = False
# FIXME, figure out why daemon=True causes reader thread to exit too early
- self._rxThread = threading.Thread(target=self.__reader, args=())
+ self._rxThread = threading.Thread(target=self.__reader, args=(), daemon=True)
MeshInterface.__init__(self, debugOut=debugOut, noProto=noProto)
@@ -2378,6 +2552,7 @@ start the reading thread later.
sendPosition
sendText
showInfo
+showNodes
waitForConfig
@@ -2457,6 +2632,7 @@ hostname {string} – Hostname/IP address of the device to connect tosendPosition
sendText
showInfo
+showNodes
waitForConfig
@@ -2528,6 +2704,7 @@ hostname {string} – Hostname/IP address of the device to connect tosendPosition
sendText
showInfo
+showNodes
waitForConfig
diff --git a/docs/meshtastic/mesh_pb2.html b/docs/meshtastic/mesh_pb2.html
index 3070ba9..a3f8e4a 100644
--- a/docs/meshtastic/mesh_pb2.html
+++ b/docs/meshtastic/mesh_pb2.html
@@ -50,7 +50,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\"\x81\x01\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\x12 \n\x08hw_model\x18\x06 \x01(\x0e\x32\x0e.HardwareModel\x12\x13\n\x0bis_licensed\x18\x07 \x01(\x08\"\x1f\n\x0eRouteDiscovery\x12\r\n\x05route\x18\x02 \x03(\x07\"\xc5\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\"\xb4\x01\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\x12\x0f\n\x0bNO_RESPONSE\x10\x08\x12\x0f\n\x0b\x42\x41\x44_REQUEST\x10 \x12\x12\n\x0eNOT_AUTHORIZED\x10!B\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\"\xe0\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\x12\x0f\n\x07rx_rssi\x18\r \x01(\x05\"[\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\"j\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\x12\n\nlast_heard\x18\x04 \x01(\x07\"\xcb\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\x1f\n\x13hw_model_deprecated\x18\x05 \x01(\tB\x02\x18\x01\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\x14\n\x0creboot_count\x18\n \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\"\x82\x01\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\x12\x14\n\ndisconnect\x18h \x01(\x08H\x00\x42\x10\n\x0epayloadVariantJ\x04\x08\x01\x10\x02J\x04\x08\x65\x10\x66J\x04\x08\x66\x10gJ\x04\x08g\x10h*\xfd\x01\n\rHardwareModel\x12\t\n\x05UNSET\x10\x00\x12\x0c\n\x08TLORA_V2\x10\x01\x12\x0c\n\x08TLORA_V1\x10\x02\x12\x12\n\x0eTLORA_V2_1_1p6\x10\x03\x12\t\n\x05TBEAM\x10\x04\x12\n\n\x06HELTEC\x10\x05\x12\x0c\n\x08TBEAM0p7\x10\x06\x12\n\n\x06T_ECHO\x10\x07\x12\x10\n\x0cTLORA_V1_1p3\x10\x08\x12\x11\n\rLORA_RELAY_V1\x10 \x12\x0e\n\nNRF52840DK\x10!\x12\x07\n\x03PPR\x10\"\x12\x0f\n\x0bGENIEBLOCKS\x10#\x12\x11\n\rNRF52_UNKNOWN\x10$\x12\r\n\tPORTDUINO\x10%\x12\x0f\n\x0b\x41NDROID_SIM\x10&*.\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'
+ 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\"\x81\x01\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\x12 \n\x08hw_model\x18\x06 \x01(\x0e\x32\x0e.HardwareModel\x12\x13\n\x0bis_licensed\x18\x07 \x01(\x08\"\x1f\n\x0eRouteDiscovery\x12\r\n\x05route\x18\x02 \x03(\x07\"\xc5\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\"\xb4\x01\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\x12\x0f\n\x0bNO_RESPONSE\x10\x08\x12\x0f\n\x0b\x42\x41\x44_REQUEST\x10 \x12\x12\n\x0eNOT_AUTHORIZED\x10!B\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\"\xe0\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\x12\x0f\n\x07rx_rssi\x18\r \x01(\x05\"[\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\"j\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\x12\n\nlast_heard\x18\x04 \x01(\x07\"\xcb\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\x1f\n\x13hw_model_deprecated\x18\x05 \x01(\tB\x02\x18\x01\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\x14\n\x0creboot_count\x18\n \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\"\xe1\x01\n\x07ToRadio\x12\x1d\n\x06packet\x18\x02 \x01(\x0b\x32\x0b.MeshPacketH\x00\x12&\n\tpeer_info\x18\x03 \x01(\x0b\x32\x11.ToRadio.PeerInfoH\x00\x12\x18\n\x0ewant_config_id\x18\x64 \x01(\rH\x00\x12\x14\n\ndisconnect\x18h \x01(\x08H\x00\x1a\x35\n\x08PeerInfo\x12\x13\n\x0b\x61pp_version\x18\x01 \x01(\r\x12\x14\n\x0cmqtt_gateway\x18\x02 \x01(\x08\x42\x10\n\x0epayloadVariantJ\x04\x08\x01\x10\x02J\x04\x08\x65\x10\x66J\x04\x08\x66\x10gJ\x04\x08g\x10h*\x8a\x02\n\rHardwareModel\x12\t\n\x05UNSET\x10\x00\x12\x0c\n\x08TLORA_V2\x10\x01\x12\x0c\n\x08TLORA_V1\x10\x02\x12\x12\n\x0eTLORA_V2_1_1p6\x10\x03\x12\t\n\x05TBEAM\x10\x04\x12\n\n\x06HELTEC\x10\x05\x12\x0c\n\x08TBEAM0p7\x10\x06\x12\n\n\x06T_ECHO\x10\x07\x12\x10\n\x0cTLORA_V1_1p3\x10\x08\x12\x0b\n\x07RAK4631\x10\t\x12\x11\n\rLORA_RELAY_V1\x10 \x12\x0e\n\nNRF52840DK\x10!\x12\x07\n\x03PPR\x10\"\x12\x0f\n\x0bGENIEBLOCKS\x10#\x12\x11\n\rNRF52_UNKNOWN\x10$\x12\r\n\tPORTDUINO\x10%\x12\x0f\n\x0b\x41NDROID_SIM\x10&*.\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,])
@@ -107,45 +107,50 @@ _HARDWAREMODEL = _descriptor.EnumDescriptor(
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
- name='LORA_RELAY_V1', index=9, number=32,
+ name='RAK4631', index=9, number=9,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
- name='NRF52840DK', index=10, number=33,
+ name='LORA_RELAY_V1', index=10, number=32,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
- name='PPR', index=11, number=34,
+ name='NRF52840DK', index=11, number=33,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
- name='GENIEBLOCKS', index=12, number=35,
+ name='PPR', index=12, number=34,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
- name='NRF52_UNKNOWN', index=13, number=36,
+ name='GENIEBLOCKS', index=13, number=35,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
- name='PORTDUINO', index=14, number=37,
+ name='NRF52_UNKNOWN', index=14, number=36,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
_descriptor.EnumValueDescriptor(
- name='ANDROID_SIM', index=15, number=38,
+ name='PORTDUINO', index=15, number=37,
+ serialized_options=None,
+ type=None,
+ create_key=_descriptor._internal_create_key),
+ _descriptor.EnumValueDescriptor(
+ name='ANDROID_SIM', index=16, number=38,
serialized_options=None,
type=None,
create_key=_descriptor._internal_create_key),
],
containing_type=None,
serialized_options=None,
- serialized_start=2119,
- serialized_end=2372,
+ serialized_start=2214,
+ serialized_end=2480,
)
_sym_db.RegisterEnumDescriptor(_HARDWAREMODEL)
@@ -170,8 +175,8 @@ _CONSTANTS = _descriptor.EnumDescriptor(
],
containing_type=None,
serialized_options=None,
- serialized_start=2374,
- serialized_end=2420,
+ serialized_start=2482,
+ serialized_end=2528,
)
_sym_db.RegisterEnumDescriptor(_CONSTANTS)
@@ -236,8 +241,8 @@ _CRITICALERRORCODE = _descriptor.EnumDescriptor(
],
containing_type=None,
serialized_options=None,
- serialized_start=2423,
- serialized_end=2612,
+ serialized_start=2531,
+ serialized_end=2720,
)
_sym_db.RegisterEnumDescriptor(_CRITICALERRORCODE)
@@ -251,6 +256,7 @@ HELTEC = 5
TBEAM0p7 = 6
T_ECHO = 7
TLORA_V1_1p3 = 8
+RAK4631 = 9
LORA_RELAY_V1 = 32
NRF52840DK = 33
PPR = 34
@@ -1145,6 +1151,44 @@ _FROMRADIO = _descriptor.Descriptor(
)
+_TORADIO_PEERINFO = _descriptor.Descriptor(
+ name='PeerInfo',
+ full_name='ToRadio.PeerInfo',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ create_key=_descriptor._internal_create_key,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='app_version', full_name='ToRadio.PeerInfo.app_version', index=0,
+ number=1, type=13, cpp_type=3, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
+ _descriptor.FieldDescriptor(
+ name='mqtt_gateway', full_name='ToRadio.PeerInfo.mqtt_gateway', index=1,
+ number=2, type=8, cpp_type=7, label=1,
+ has_default_value=False, default_value=False,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ serialized_options=None,
+ is_extendable=False,
+ syntax='proto3',
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=2116,
+ serialized_end=2169,
+)
+
_TORADIO = _descriptor.Descriptor(
name='ToRadio',
full_name='ToRadio',
@@ -1161,14 +1205,21 @@ _TORADIO = _descriptor.Descriptor(
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
- name='want_config_id', full_name='ToRadio.want_config_id', index=1,
+ name='peer_info', full_name='ToRadio.peer_info', index=1,
+ number=3, type=11, cpp_type=10, label=1,
+ has_default_value=False, default_value=None,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
+ _descriptor.FieldDescriptor(
+ name='want_config_id', full_name='ToRadio.want_config_id', index=2,
number=100, type=13, cpp_type=3, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key),
_descriptor.FieldDescriptor(
- name='disconnect', full_name='ToRadio.disconnect', index=2,
+ name='disconnect', full_name='ToRadio.disconnect', index=3,
number=104, type=8, cpp_type=7, label=1,
has_default_value=False, default_value=False,
message_type=None, enum_type=None, containing_type=None,
@@ -1177,7 +1228,7 @@ _TORADIO = _descriptor.Descriptor(
],
extensions=[
],
- nested_types=[],
+ nested_types=[_TORADIO_PEERINFO, ],
enum_types=[
],
serialized_options=None,
@@ -1192,7 +1243,7 @@ _TORADIO = _descriptor.Descriptor(
fields=[]),
],
serialized_start=1986,
- serialized_end=2116,
+ serialized_end=2211,
)
_USER.fields_by_name['hw_model'].enum_type = _HARDWAREMODEL
@@ -1246,10 +1297,15 @@ _FROMRADIO.fields_by_name['config_complete_id'].containing_oneof = _FROM
_FROMRADIO.oneofs_by_name['payloadVariant'].fields.append(
_FROMRADIO.fields_by_name['rebooted'])
_FROMRADIO.fields_by_name['rebooted'].containing_oneof = _FROMRADIO.oneofs_by_name['payloadVariant']
+_TORADIO_PEERINFO.containing_type = _TORADIO
_TORADIO.fields_by_name['packet'].message_type = _MESHPACKET
+_TORADIO.fields_by_name['peer_info'].message_type = _TORADIO_PEERINFO
_TORADIO.oneofs_by_name['payloadVariant'].fields.append(
_TORADIO.fields_by_name['packet'])
_TORADIO.fields_by_name['packet'].containing_oneof = _TORADIO.oneofs_by_name['payloadVariant']
+_TORADIO.oneofs_by_name['payloadVariant'].fields.append(
+ _TORADIO.fields_by_name['peer_info'])
+_TORADIO.fields_by_name['peer_info'].containing_oneof = _TORADIO.oneofs_by_name['payloadVariant']
_TORADIO.oneofs_by_name['payloadVariant'].fields.append(
_TORADIO.fields_by_name['want_config_id'])
_TORADIO.fields_by_name['want_config_id'].containing_oneof = _TORADIO.oneofs_by_name['payloadVariant']
@@ -1343,11 +1399,19 @@ FromRadio = _reflection.GeneratedProtocolMessageType('FromRadio', (_mess
_sym_db.RegisterMessage(FromRadio)
ToRadio = _reflection.GeneratedProtocolMessageType('ToRadio', (_message.Message,), {
+
+ 'PeerInfo' : _reflection.GeneratedProtocolMessageType('PeerInfo', (_message.Message,), {
+ 'DESCRIPTOR' : _TORADIO_PEERINFO,
+ '__module__' : 'mesh_pb2'
+ # @@protoc_insertion_point(class_scope:ToRadio.PeerInfo)
+ })
+ ,
'DESCRIPTOR' : _TORADIO,
'__module__' : 'mesh_pb2'
# @@protoc_insertion_point(class_scope:ToRadio)
})
_sym_db.RegisterMessage(ToRadio)
+_sym_db.RegisterMessage(ToRadio.PeerInfo)
DESCRIPTOR._options = None
@@ -1916,6 +1980,10 @@ _MYNODEINFO.fields_by_name['hw_model_deprecated']._options = None
+var PeerInfo
+
+
+
Instance variables
@@ -1927,6 +1995,10 @@ _MYNODEINFO.fields_by_name['hw_model_deprecated']._options = None
-
+var peer_info
+-
+
+
var want_config_id
-
Field ToRadio.want_config_id
@@ -2135,10 +2207,12 @@ _MYNODEINFO.fields_by_name['hw_model_deprecated']._options = None
-
-
diff --git a/docs/meshtastic/test.html b/docs/meshtastic/test.html
index 653ca1b..d6ee1f1 100644
--- a/docs/meshtastic/test.html
+++ b/docs/meshtastic/test.html
@@ -32,7 +32,7 @@ from . import SerialInterface, TCPInterface, BROADCAST_NUM
from pubsub import pub
import time
import sys
-import threading
+import threading, traceback
from dotmap import DotMap
"""The interfaces we are using for our tests"""
@@ -195,13 +195,18 @@ def testSimulator():
"""
logging.basicConfig(level=logging.DEBUG if False else logging.INFO)
logging.info("Connecting to simulator on localhost!")
- iface = TCPInterface("localhost")
- iface.showInfo()
- iface.localNode.showInfo()
- iface.localNode.exitSimulator()
- iface.close()
- logging.info("Integration test successful!")
- sys.exit(0)
+ try:
+ iface = TCPInterface("localhost")
+ iface.showInfo()
+ iface.localNode.showInfo()
+ iface.localNode.exitSimulator()
+ iface.close()
+ logging.info("Integration test successful!")
+ sys.exit(0)
+ except:
+ print("Error while testing simulator:", sys.exc_info()[0])
+ traceback.print_exc()
+ sys.exit(1)
@@ -453,13 +458,18 @@ python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
+ try:
+ iface = TCPInterface("localhost")
+ iface.showInfo()
+ iface.localNode.showInfo()
+ iface.localNode.exitSimulator()
+ iface.close()
+ logging.info("Integration test successful!")
+ sys.exit(0)
+ except:
+ print("Error while testing simulator:", sys.exc_info()[0])
+ traceback.print_exc()
+ sys.exit(1)
diff --git a/setup.py b/setup.py
index bf99f45..23e7043 100644
--- a/setup.py
+++ b/setup.py
@@ -12,7 +12,7 @@ with open("README.md", "r") as fh:
# This call to setup() does all the work
setup(
name="meshtastic",
- version="1.2.25",
+ version="1.2.29",
description="Python API & client shell for talking to Meshtastic devices",
long_description=long_description,
long_description_content_type="text/markdown",