From 61eb25136993517ef819c5262938a42481ae3fd9 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 27 Mar 2021 10:31:48 +0800 Subject: [PATCH] reformat code --- meshtastic/__init__.py | 68 ++++++++++++++++++++++++++--------------- meshtastic/__main__.py | 59 +++++++++++++++++++++++------------ meshtastic/admin_pb2.py | 14 +++++++-- meshtastic/mesh_pb2.py | 43 +++++++++++++++----------- meshtastic/test.py | 14 ++++++--- meshtastic/util.py | 4 ++- proto | 2 +- 7 files changed, 132 insertions(+), 72 deletions(-) diff --git a/meshtastic/__init__.py b/meshtastic/__init__.py index 3cdd747..b19d3ca 100644 --- a/meshtastic/__init__.py +++ b/meshtastic/__init__.py @@ -97,6 +97,7 @@ OUR_APP_VERSION = 20200 publishingThread = DeferredExecution("publishing") + class ResponseHandler(NamedTuple): """A pending response callback, waiting for a response to one of our messages""" # requestId: int - used only as a key @@ -127,7 +128,7 @@ def pskToString(psk: bytes): """Given an array of PSK bytes, decode them into a human readable (but privacy protecting) string""" if len(psk) == 0: return "unencrypted" - elif len(psk) == 1: + elif len(psk) == 1: b = psk[0] if b == 0: return "unencrypted" @@ -138,6 +139,7 @@ def pskToString(psk: bytes): else: return "secret" + class Node: """A model of a (local or remote) node in the mesh @@ -157,19 +159,20 @@ class Node: for c in self.channels: if c.role != channel_pb2.Channel.Role.DISABLED: cStr = stripnl(MessageToJson(c.settings)) - print(f" {channel_pb2.Channel.Role.Name(c.role)} psk={pskToString(c.settings.psk)} {cStr}") - publicURL = self.getURL(includeAll = False) - adminURL = self.getURL(includeAll = True) + print( + f" {channel_pb2.Channel.Role.Name(c.role)} psk={pskToString(c.settings.psk)} {cStr}") + publicURL = self.getURL(includeAll=False) + adminURL = self.getURL(includeAll=True) print(f"\nPrimary channel URL: {publicURL}") if adminURL != publicURL: print(f"Complete URL (includes all channels): {adminURL}") def showInfo(self): """Show human readable description of our node""" - print(f"Preferences: {stripnl(MessageToJson(self.radioConfig.preferences))}\n") + print( + f"Preferences: {stripnl(MessageToJson(self.radioConfig.preferences))}\n") self.showChannels() - def requestConfig(self): """ Send regular MeshPackets to ask for settings and channels @@ -195,7 +198,7 @@ class Node: self._sendAdmin(p) logging.debug("Wrote config") - def writeChannel(self, channelIndex, adminIndex = 0): + def writeChannel(self, channelIndex, adminIndex=0): """Write the current (edited) channel to the device""" p = admin_pb2.AdminMessage() @@ -215,7 +218,7 @@ class Node: adminIndex = self.iface.localNode._getAdminChannelIndex() self.channels.pop(channelIndex) - self._fixupChannels() # expand back to 8 channels + self._fixupChannels() # expand back to 8 channels index = channelIndex while index < self.iface.myInfo.max_channels: @@ -224,7 +227,8 @@ class Node: # if we are updating the local node, we might end up *moving* the admin channel index as we are writing if (self.iface.localNode == self) and index >= adminIndex: - adminIndex = 0 # We've now passed the old location for admin index (and writen it), so we can start finding it by name again + # We've now passed the old location for admin index (and writen it), so we can start finding it by name again + adminIndex = 0 def getChannelByName(self, name): """Try to find the named channel or return None""" @@ -332,7 +336,7 @@ class Node: """A closure to handle the response packet""" self.radioConfig = p["decoded"]["admin"]["raw"].get_radio_response logging.debug("Received radio config, now fetching channels...") - self._requestChannel(0) # now start fetching channels + self._requestChannel(0) # now start fetching channels return self._sendAdmin(p, wantResponse=True, @@ -345,14 +349,24 @@ class Node: p = admin_pb2.AdminMessage() p.exit_simulator = True - return self._sendAdmin(p) + return self._sendAdmin(p) + + def reboot(self, secs: int = 10): + """ + Tell the node to reboot + """ + p = admin_pb2.AdminMessage() + p.reboot_seconds = secs + logging.info(f"Telling node to reboot in {secs} seconds") + + return self._sendAdmin(p) def _fixupChannels(self): """Fixup indexes and add disabled channels as needed""" # Add extra disabled channels as needed for index, ch in enumerate(self.channels): - ch.index = index # fixup indexes + ch.index = index # fixup indexes self._fillChannels() @@ -406,11 +420,11 @@ class Node: onResponse=onResponse) def _sendAdmin(self, p: admin_pb2.AdminMessage, wantResponse=False, - onResponse=None, + onResponse=None, adminIndex=0): """Send an admin message to the specified node (or the local node if destNodeNum is zero)""" - if adminIndex == 0: # unless a special channel index was used, we want to use the admin index + if adminIndex == 0: # unless a special channel index was used, we want to use the admin index adminIndex = self.iface.localNode._getAdminChannelIndex() return self.iface.sendData(p, self.nodeNum, @@ -476,10 +490,11 @@ class MeshInterface: if nodeId == LOCAL_ADDR: return self.localNode else: - logging.info("Requesting configuration from remote node (this could take a while)") + logging.info( + "Requesting configuration from remote node (this could take a while)") n = Node(self, nodeId) n.requestConfig() - if not n.waitForConfig(maxsecs = 60): + if not n.waitForConfig(maxsecs=60): raise Exception("Timed out waiting for node config") return n @@ -606,7 +621,8 @@ class MeshInterface: nodeNum = BROADCAST_NUM elif destinationId == LOCAL_ADDR: nodeNum = self.myInfo.my_node_num - elif destinationId.startswith("!"): # A simple hex style nodeid - we can parse this without needing the DB + # A simple hex style nodeid - we can parse this without needing the DB + elif destinationId.startswith("!"): nodeNum = int(destinationId[1:], 16) else: node = self.nodes.get(destinationId) @@ -630,7 +646,8 @@ class MeshInterface: def waitForConfig(self): """Block until radio config is received. Returns True if config has been received.""" - success = waitForSet(self, attrs=('myInfo', 'nodes')) and self.localNode.waitForConfig() + success = waitForSet(self, attrs=('myInfo', 'nodes') + ) and self.localNode.waitForConfig() if not success: raise Exception("Timed out waiting for interface config") @@ -700,7 +717,7 @@ class MeshInterface: startConfig = mesh_pb2.ToRadio() self.configId = random.randint(0, 0xffffffff) - startConfig.want_config_id = self.configId + startConfig.want_config_id = self.configId self._sendToRadio(startConfig) def _sendDisconnect(self): @@ -769,7 +786,7 @@ class MeshInterface: if "user" in node: # Some nodes might not have user/ids assigned yet self.nodes[node["user"]["id"]] = node publishingThread.queueWork(lambda: pub.sendMessage("meshtastic.node.updated", - node=node, interface=self)) + node=node, interface=self)) elif fromRadio.config_complete_id == self.configId: # we ignore the config_complete_id, it is unneeded for our stream API fromRadio.config_complete_id logging.debug(f"Config complete ID {self.configId}") @@ -856,7 +873,7 @@ class MeshInterface: asDict["fromId"] = self._nodeNumToId(asDict["from"]) except Exception as ex: logging.warn(f"Not populating fromId {ex}") - try: + try: asDict["toId"] = self._nodeNumToId(asDict["to"]) except Exception as ex: logging.warn(f"Not populating toId {ex}") @@ -953,7 +970,7 @@ class BLEInterface(MeshInterface): self.device.char_write(TORADIO_UUID, b) def close(self): - MeshInterface.close(self) + MeshInterface.close(self) self.adapter.stop() def _readFromRadio(self): @@ -964,6 +981,7 @@ class BLEInterface(MeshInterface): if not wasEmpty: self._handleFromRadio(b) + class StreamInterface(MeshInterface): """Interface class for meshtastic devices over a stream link (serial, TCP, etc)""" @@ -1022,7 +1040,7 @@ class StreamInterface(MeshInterface): def _writeBytes(self, b): """Write an array of bytes to our stream and flush""" - if self.stream: # ignore writes when stream is closed + if self.stream: # ignore writes when stream is closed self.stream.write(b) self.stream.flush() @@ -1042,7 +1060,7 @@ class StreamInterface(MeshInterface): def close(self): """Close a connection to the device""" logging.debug("Closing stream") - MeshInterface.close(self) + MeshInterface.close(self) # pyserial cancel_read doesn't seem to work, therefore we ask the reader thread to close things for us self._wantExit = True if self._rxThread != threading.current_thread(): @@ -1181,7 +1199,7 @@ class TCPInterface(StreamInterface): def close(self): """Close a connection to the device""" logging.debug("Closing TCP stream") - StreamInterface.close(self) + StreamInterface.close(self) # Sometimes the socket read might be blocked in the reader thread. Therefore we force the shutdown by closing # the socket here self._wantExit = True diff --git a/meshtastic/__main__.py b/meshtastic/__main__.py index 205f49c..741a378 100644 --- a/meshtastic/__main__.py +++ b/meshtastic/__main__.py @@ -2,7 +2,11 @@ import argparse import platform -import logging, sys, codecs, base64, os +import logging +import sys +import codecs +import base64 +import os from . import SerialInterface, TCPInterface, BLEInterface, test, remote_hardware from pubsub import pub from . import mesh_pb2, portnums_pb2, channel_pb2 @@ -61,9 +65,11 @@ def onConnection(interface, topic=pub.AUTO_TOPIC): trueTerms = {"t", "true", "yes"} falseTerms = {"f", "false", "no"} + def genPSKS256(): return os.urandom(32) + def fromPSK(valstr): """A special version of fromStr that assumes the user is trying to set a PSK. In that case we also allow "none", "default" or "random" (to have python generate one), or simpleN @@ -75,10 +81,12 @@ def fromPSK(valstr): elif valstr == "default": return bytes([1]) # Use default channel psk elif valstr.startswith("simple"): - return bytes([int(valstr[6:]) + 1]) # Use one of the single byte encodings + # Use one of the single byte encodings + return bytes([int(valstr[6:]) + 1]) else: return fromStr(valstr) + def fromStr(valstr): """try to parse as int, float or bool (and fallback to a string as last resort) @@ -206,8 +214,10 @@ def setPref(attributes, name, valStr): except Exception as ex: print(f"Can't set {name} due to {ex}") + targetNode = None + def onConnected(interface): """Callback invoked when we connect to a radio""" closeNow = False # Should we drop the connection after we finish? @@ -228,7 +238,7 @@ def onConnected(interface): alt = 0 lat = 0.0 lon = 0.0 - time = 0 # always set time, but based on the local clock + time = 0 # always set time, but based on the local clock prefs = interface.localNode.radioConfig.preferences if args.setalt: alt = int(args.setalt) @@ -258,13 +268,19 @@ def onConnected(interface): if args.set_ham: closeNow = True - print(f"Setting HAM ID to {args.set_ham} and turning off encryption") + print( + f"Setting HAM ID to {args.set_ham} and turning off encryption") getNode().setOwner(args.set_ham) - ch = getNode().channels[0] # Must turn off crypt on primary channel + # Must turn off crypt on primary channel + ch = getNode().channels[0] ch.settings.psk = fromPSK("none") print(f"Writing modified channels to device") getNode().writeChannel(0) + if args.reboot: + closeNow = True + getNode().reboot() + if args.sendtext: closeNow = True print(f"Sending text message {args.sendtext} to {args.destOrAll}") @@ -324,7 +340,8 @@ def onConnected(interface): n = getNode() ch = n.getChannelByName(args.ch_add) if ch: - logging.error(f"This node already has a '{args.ch_add}' channel - no changes.") + logging.error( + f"This node already has a '{args.ch_add}' channel - no changes.") else: ch = n.getDisabledChannel() if not ch: @@ -333,7 +350,7 @@ def onConnected(interface): chs.psk = genPSKS256() chs.name = args.ch_add ch.settings.CopyFrom(chs) - ch.role = channel_pb2.Channel.Role.SECONDARY + ch.role = channel_pb2.Channel.Role.SECONDARY print(f"Writing modified channels to device") n.writeChannel(ch.index) @@ -348,13 +365,14 @@ def onConnected(interface): ch = getNode().channels[channelIndex] - enable = args.ch_enable # should we enable this channel? + enable = args.ch_enable # should we enable this channel? if args.ch_longslow or args.ch_shortfast: if channelIndex != 0: - raise Exception("standard channel settings can only be applied to the PRIMARY channel") + raise Exception( + "standard channel settings can only be applied to the PRIMARY channel") - enable = True # force enable + enable = True # force enable def setSimpleChannel(modem_config): """Set one of the simple modem_config only based channels""" @@ -378,13 +396,14 @@ def onConnected(interface): # Handle the channel settings for pref in (args.ch_set or []): if pref[0] == "psk": - ch.settings.psk =fromPSK(pref[1]) + ch.settings.psk = fromPSK(pref[1]) else: setPref(ch.settings, pref[0], pref[1]) - enable = True # If we set any pref, assume the user wants to enable the channel + enable = True # If we set any pref, assume the user wants to enable the channel if enable: - ch.role = channel_pb2.Channel.Role.PRIMARY if (channelIndex == 0) else channel_pb2.Channel.Role.SECONDARY + ch.role = channel_pb2.Channel.Role.PRIMARY if ( + channelIndex == 0) else channel_pb2.Channel.Role.SECONDARY else: ch.role = channel_pb2.Channel.Role.DISABLED @@ -408,7 +427,7 @@ def onConnected(interface): if args.qr: closeNow = True - url = interface.localNode.getURL(includeAll = False) + url = interface.localNode.getURL(includeAll=False) print(f"Primary channel URL {url}") qr = pyqrcode.create(url) print(qr.terminal()) @@ -462,12 +481,9 @@ def common(): args.destOrLocal = args.dest # FIXME, temp hack for debugging remove if not args.seriallog: - if args.info or args.nodes or args.set or args.seturl or args.set_owner or args.setlat or args.setlon or \ - args.ch_longslow or args.ch_shortfast or args.ch_set or args.sendtext or \ - args.qr or args.ch_add or args.ch_del or args.set_ham: - args.seriallog = "none" # assume no debug output in this case - else: - args.seriallog = "stdout" # default to stdout + args.seriallog = "none" # assume no debug output in this case + else: + args.seriallog = "stdout" # default to stdout if args.deprecated != None: logging.error( @@ -573,6 +589,9 @@ def initParser(): parser.add_argument( "--sendping", help="Send a ping message (which requests a reply)", action="store_true") + parser.add_argument( + "--reboot", help="Tell the destination node to reboot", action="store_true") + # parser.add_argument( # "--repeat", help="Normally the send commands send only one message, use this option to request repeated sends") diff --git a/meshtastic/admin_pb2.py b/meshtastic/admin_pb2.py index db478fc..8272e40 100644 --- a/meshtastic/admin_pb2.py +++ b/meshtastic/admin_pb2.py @@ -22,7 +22,7 @@ DESCRIPTOR = _descriptor.FileDescriptor( syntax='proto3', serialized_options=b'\n\023com.geeksville.meshB\013AdminProtosH\003', create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x0b\x61\x64min.proto\x1a\nmesh.proto\x1a\x11radioconfig.proto\x1a\rchannel.proto\"\xe1\x02\n\x0c\x41\x64minMessage\x12!\n\tset_radio\x18\x01 \x01(\x0b\x32\x0c.RadioConfigH\x00\x12\x1a\n\tset_owner\x18\x02 \x01(\x0b\x32\x05.UserH\x00\x12\x1f\n\x0bset_channel\x18\x03 \x01(\x0b\x32\x08.ChannelH\x00\x12\x1b\n\x11get_radio_request\x18\x04 \x01(\x08H\x00\x12*\n\x12get_radio_response\x18\x05 \x01(\x0b\x32\x0c.RadioConfigH\x00\x12\x1d\n\x13get_channel_request\x18\x06 \x01(\rH\x00\x12(\n\x14get_channel_response\x18\x07 \x01(\x0b\x32\x08.ChannelH\x00\x12\x1d\n\x13\x63onfirm_set_channel\x18 \x01(\x08H\x00\x12\x1b\n\x11\x63onfirm_set_radio\x18! \x01(\x08H\x00\x12\x18\n\x0e\x65xit_simulator\x18\" \x01(\x08H\x00\x42\t\n\x07variantB$\n\x13\x63om.geeksville.meshB\x0b\x41\x64minProtosH\x03\x62\x06proto3' + serialized_pb=b'\n\x0b\x61\x64min.proto\x1a\nmesh.proto\x1a\x11radioconfig.proto\x1a\rchannel.proto\"\xfb\x02\n\x0c\x41\x64minMessage\x12!\n\tset_radio\x18\x01 \x01(\x0b\x32\x0c.RadioConfigH\x00\x12\x1a\n\tset_owner\x18\x02 \x01(\x0b\x32\x05.UserH\x00\x12\x1f\n\x0bset_channel\x18\x03 \x01(\x0b\x32\x08.ChannelH\x00\x12\x1b\n\x11get_radio_request\x18\x04 \x01(\x08H\x00\x12*\n\x12get_radio_response\x18\x05 \x01(\x0b\x32\x0c.RadioConfigH\x00\x12\x1d\n\x13get_channel_request\x18\x06 \x01(\rH\x00\x12(\n\x14get_channel_response\x18\x07 \x01(\x0b\x32\x08.ChannelH\x00\x12\x1d\n\x13\x63onfirm_set_channel\x18 \x01(\x08H\x00\x12\x1b\n\x11\x63onfirm_set_radio\x18! \x01(\x08H\x00\x12\x18\n\x0e\x65xit_simulator\x18\" \x01(\x08H\x00\x12\x18\n\x0ereboot_seconds\x18# \x01(\x05H\x00\x42\t\n\x07variantB$\n\x13\x63om.geeksville.meshB\x0b\x41\x64minProtosH\x03\x62\x06proto3' , dependencies=[mesh__pb2.DESCRIPTOR,radioconfig__pb2.DESCRIPTOR,channel__pb2.DESCRIPTOR,]) @@ -107,6 +107,13 @@ _ADMINMESSAGE = _descriptor.Descriptor( 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='reboot_seconds', full_name='AdminMessage.reboot_seconds', index=10, + number=35, 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, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -125,7 +132,7 @@ _ADMINMESSAGE = _descriptor.Descriptor( fields=[]), ], serialized_start=62, - serialized_end=415, + serialized_end=441, ) _ADMINMESSAGE.fields_by_name['set_radio'].message_type = radioconfig__pb2._RADIOCONFIG @@ -163,6 +170,9 @@ _ADMINMESSAGE.fields_by_name['confirm_set_radio'].containing_oneof = _ADMINMESSA _ADMINMESSAGE.oneofs_by_name['variant'].fields.append( _ADMINMESSAGE.fields_by_name['exit_simulator']) _ADMINMESSAGE.fields_by_name['exit_simulator'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant'] +_ADMINMESSAGE.oneofs_by_name['variant'].fields.append( + _ADMINMESSAGE.fields_by_name['reboot_seconds']) +_ADMINMESSAGE.fields_by_name['reboot_seconds'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant'] DESCRIPTOR.message_types_by_name['AdminMessage'] = _ADMINMESSAGE _sym_db.RegisterFileDescriptor(DESCRIPTOR) diff --git a/meshtastic/mesh_pb2.py b/meshtastic/mesh_pb2.py index 2c2b0df..66cb97a 100644 --- a/meshtastic/mesh_pb2.py +++ b/meshtastic/mesh_pb2.py @@ -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\"l\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\"\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\"V\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\"\xb5\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\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\"l\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\"\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\"\xb5\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\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' , dependencies=[portnums__pb2.DESCRIPTOR,]) @@ -115,8 +115,8 @@ _HARDWAREMODEL = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=2055, - serialized_end=2308, + serialized_start=2075, + serialized_end=2328, ) _sym_db.RegisterEnumDescriptor(_HARDWAREMODEL) @@ -141,8 +141,8 @@ _CONSTANTS = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=2310, - serialized_end=2356, + serialized_start=2330, + serialized_end=2376, ) _sym_db.RegisterEnumDescriptor(_CONSTANTS) @@ -207,8 +207,8 @@ _CRITICALERRORCODE = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=2359, - serialized_end=2548, + serialized_start=2379, + serialized_end=2568, ) _sym_db.RegisterEnumDescriptor(_CRITICALERRORCODE) @@ -408,8 +408,8 @@ _LOGRECORD_LEVEL = _descriptor.EnumDescriptor( ], containing_type=None, serialized_options=None, - serialized_start=1595, - serialized_end=1683, + serialized_start=1615, + serialized_end=1703, ) _sym_db.RegisterEnumDescriptor(_LOGRECORD_LEVEL) @@ -836,6 +836,13 @@ _NODEINFO = _descriptor.Descriptor( 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='last_heard', full_name='NodeInfo.last_heard', index=4, + number=4, type=7, 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), ], extensions=[ ], @@ -849,7 +856,7 @@ _NODEINFO = _descriptor.Descriptor( oneofs=[ ], serialized_start=1101, - serialized_end=1187, + serialized_end=1207, ) @@ -957,8 +964,8 @@ _MYNODEINFO = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1190, - serialized_end=1499, + serialized_start=1210, + serialized_end=1519, ) @@ -1011,8 +1018,8 @@ _LOGRECORD = _descriptor.Descriptor( extension_ranges=[], oneofs=[ ], - serialized_start=1502, - serialized_end=1683, + serialized_start=1522, + serialized_end=1703, ) @@ -1090,8 +1097,8 @@ _FROMRADIO = _descriptor.Descriptor( create_key=_descriptor._internal_create_key, fields=[]), ], - serialized_start=1686, - serialized_end=1919, + serialized_start=1706, + serialized_end=1939, ) @@ -1141,8 +1148,8 @@ _TORADIO = _descriptor.Descriptor( create_key=_descriptor._internal_create_key, fields=[]), ], - serialized_start=1922, - serialized_end=2052, + serialized_start=1942, + serialized_end=2072, ) _USER.fields_by_name['hw_model'].enum_type = _HARDWAREMODEL diff --git a/meshtastic/test.py b/meshtastic/test.py index 250813f..1a65e88 100644 --- a/meshtastic/test.py +++ b/meshtastic/test.py @@ -23,7 +23,7 @@ sendingInterface = None def onReceive(packet, interface): """Callback invoked when a packet arrives""" if sendingInterface == interface: - pass + pass # print("Ignoring sending interface") else: # print(f"From {interface.stream.port}: {packet}") @@ -65,7 +65,8 @@ def testSend(fromInterface, toInterface, isBroadcast=False, asBinary=False, want else: toNode = toInterface.myInfo.my_node_num - logging.debug(f"Sending test wantAck={wantAck} packet from {fromNode} to {toNode}") + logging.debug( + f"Sending test wantAck={wantAck} packet from {fromNode} to {toNode}") global sendingInterface sendingInterface = fromInterface if not asBinary: @@ -100,7 +101,7 @@ def runTests(numTests=50, wantAck=False, maxFailures=0): logging.info( f"Test succeeded {numSuccess} successes {numFail} failures so far") - #if numFail >= 3: + # if numFail >= 3: # for i in interfaces: # i.close() # return @@ -112,10 +113,12 @@ def runTests(numTests=50, wantAck=False, maxFailures=0): return numFail + def testThread(numTests=50): logging.info("Found devices, starting tests...") runTests(numTests, wantAck=True) - runTests(numTests, wantAck=False, maxFailures=5) # Allow a few dropped packets + # Allow a few dropped packets + runTests(numTests, wantAck=False, maxFailures=5) def onConnection(topic=pub.AUTO_TOPIC): @@ -152,6 +155,7 @@ def testAll(): for i in interfaces: i.close() + def testSimulator(): """ Assume that someone has launched meshtastic-native as a simulated node. @@ -169,4 +173,4 @@ def testSimulator(): iface.localNode.exitSimulator() iface.close() logging.info("Integration test successful!") - sys.exit(0) \ No newline at end of file + sys.exit(0) diff --git a/meshtastic/util.py b/meshtastic/util.py index fe971b1..decccc5 100644 --- a/meshtastic/util.py +++ b/meshtastic/util.py @@ -3,7 +3,9 @@ from collections import defaultdict import serial import serial.tools.list_ports from queue import Queue -import threading, sys, logging +import threading +import sys +import logging """Some devices such as a seger jlink we never want to accidentally open""" blacklistVids = dict.fromkeys([0x1366]) diff --git a/proto b/proto index e8d2a96..f9c4f87 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit e8d2a96a00713608ba4a6a36c9bea4ce06886619 +Subproject commit f9c4f875818c9aa6995e6e25803d52557a1779c7