From e6d61c66034824f2db7c380f4e13f10b11e96053 Mon Sep 17 00:00:00 2001 From: Ian McEwen Date: Wed, 5 Jun 2024 18:52:35 -0700 Subject: [PATCH] Allow a faster nodedb-less startup on 2.3.11+ with `--no-nodes` and the magic value from meshtastic/firmware#3949 --- meshtastic/__init__.py | 3 +++ meshtastic/__main__.py | 15 +++++++++++---- meshtastic/ble_interface.py | 4 ++-- meshtastic/mesh_interface.py | 11 ++++++++--- meshtastic/serial_interface.py | 4 ++-- meshtastic/stream_interface.py | 4 ++-- meshtastic/tcp_interface.py | 3 ++- 7 files changed, 30 insertions(+), 14 deletions(-) diff --git a/meshtastic/__init__.py b/meshtastic/__init__.py index 29dca98..26d8e94 100644 --- a/meshtastic/__init__.py +++ b/meshtastic/__init__.py @@ -117,6 +117,9 @@ OUR_APP_VERSION = 20300 format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20 """ +NODELESS_WANT_CONFIG_ID = 69420 +"""A special thing to pass for want_config_id that instructs nodes to skip sending nodeinfos other than its own.""" + publishingThread = DeferredExecution("publishing") diff --git a/meshtastic/__main__.py b/meshtastic/__main__.py index 66e7559..fa71adc 100644 --- a/meshtastic/__main__.py +++ b/meshtastic/__main__.py @@ -1050,11 +1050,11 @@ def common(): meshtastic.util.our_exit("BLE scan finished", 0) return elif args.ble: - client = BLEInterface(args.ble, debugOut=logfile, noProto=args.noproto) + client = BLEInterface(args.ble, debugOut=logfile, noProto=args.noproto, noNodes=args.no_nodes) elif args.host: try: client = meshtastic.tcp_interface.TCPInterface( - args.host, debugOut=logfile, noProto=args.noproto + args.host, debugOut=logfile, noProto=args.noproto, noNodes=args.no_nodes ) except Exception as ex: meshtastic.util.our_exit( @@ -1063,7 +1063,7 @@ def common(): else: try: client = meshtastic.serial_interface.SerialInterface( - args.port, debugOut=logfile, noProto=args.noproto + args.port, debugOut=logfile, noProto=args.noproto, noNodes=args.no_nodes ) except PermissionError as ex: username = os.getlogin() @@ -1078,7 +1078,7 @@ def common(): if client.devPath is None: try: client = meshtastic.tcp_interface.TCPInterface( - "localhost", debugOut=logfile, noProto=args.noproto + "localhost", debugOut=logfile, noProto=args.noproto, noNodes=args.no_nodes ) except Exception as ex: meshtastic.util.our_exit( @@ -1453,6 +1453,13 @@ def initParser(): action="store_true", ) + group.add_argument( + "--no-nodes", + help="Request that the node not send node info to the client. " + "Will break things that depend on the nodedb, but will speed up startup. Requires 2.3.11+ firmware.", + action="store_true", + ) + group.add_argument( "--setalt", help="Set device altitude in meters (allows use without GPS), and enable fixed position.", diff --git a/meshtastic/ble_interface.py b/meshtastic/ble_interface.py index c47ce78..1c12758 100644 --- a/meshtastic/ble_interface.py +++ b/meshtastic/ble_interface.py @@ -32,7 +32,7 @@ class BLEInterface(MeshInterface): MESH = False - def __init__(self, address: Optional[str], noProto: bool = False, debugOut = None): + def __init__(self, address: Optional[str], noProto: bool = False, debugOut = None, noNodes: bool = False): self.state = BLEInterface.BLEState() if not address: @@ -60,7 +60,7 @@ class BLEInterface(MeshInterface): return logging.debug("Mesh init starting") - MeshInterface.__init__(self, debugOut = debugOut, noProto = noProto) + MeshInterface.__init__(self, debugOut = debugOut, noProto = noProto, noNodes = noNodes) self._startConfig() if not self.noProto: self._waitConnected(timeout = 60.0) diff --git a/meshtastic/mesh_interface.py b/meshtastic/mesh_interface.py index 1c24fb9..27e0a04 100644 --- a/meshtastic/mesh_interface.py +++ b/meshtastic/mesh_interface.py @@ -26,6 +26,7 @@ from meshtastic import ( BROADCAST_ADDR, BROADCAST_NUM, LOCAL_ADDR, + NODELESS_WANT_CONFIG_ID, ResponseHandler, protocols, publishingThread, @@ -57,12 +58,14 @@ class MeshInterface: self.message = message super().__init__(self.message) - def __init__(self, debugOut=None, noProto: bool=False) -> None: + def __init__(self, debugOut=None, noProto: bool=False, noNodes: bool=False) -> None: """Constructor Keyword Arguments: noProto -- If True, don't try to run our protocol on the link - just be a dumb serial client. + noNodes -- If True, instruct the node to not send its nodedb + on startup, just other configuration information. """ self.debugOut = debugOut self.nodes: Optional[Dict[str,Dict]] = None # FIXME @@ -81,7 +84,8 @@ class MeshInterface: random.seed() # FIXME, we should not clobber the random seedval here, instead tell user they must call it self.currentPacketId: int = random.randint(0, 0xFFFFFFFF) self.nodesByNum: Optional[Dict[int, Dict]] = None - self.configId: Optional[int] = None + self.noNodes: bool = noNodes + self.configId: Optional[int] = NODELESS_WANT_CONFIG_ID if noNodes else None self.gotResponse: bool = False # used in gpio read self.mask: Optional[int] = None # used in gpio read and gpio watch self.queueStatus: Optional[mesh_pb2.QueueStatus] = None @@ -713,7 +717,8 @@ class MeshInterface: self._localChannels = [] # empty until we start getting channels pushed from the device (during config) startConfig = mesh_pb2.ToRadio() - self.configId = random.randint(0, 0xFFFFFFFF) + if self.configId is None or not self.noNodes: + self.configId = random.randint(0, 0xFFFFFFFF) startConfig.want_config_id = self.configId self._sendToRadio(startConfig) diff --git a/meshtastic/serial_interface.py b/meshtastic/serial_interface.py index 8a59cea..9a8307d 100644 --- a/meshtastic/serial_interface.py +++ b/meshtastic/serial_interface.py @@ -18,7 +18,7 @@ if platform.system() != "Windows": class SerialInterface(StreamInterface): """Interface class for meshtastic devices over a serial link""" - def __init__(self, devPath: Optional[str]=None, debugOut=None, noProto=False, connectNow=True): + def __init__(self, devPath: Optional[str]=None, debugOut=None, noProto=False, connectNow=True, noNodes: bool=False): """Constructor, opens a connection to a specified serial port, or if unspecified try to find one Meshtastic device by probing @@ -62,7 +62,7 @@ class SerialInterface(StreamInterface): time.sleep(0.1) StreamInterface.__init__( - self, debugOut=debugOut, noProto=noProto, connectNow=connectNow + self, debugOut=debugOut, noProto=noProto, connectNow=connectNow, noNodes=noNodes ) def close(self): diff --git a/meshtastic/stream_interface.py b/meshtastic/stream_interface.py index d416785..dea6923 100644 --- a/meshtastic/stream_interface.py +++ b/meshtastic/stream_interface.py @@ -19,7 +19,7 @@ MAX_TO_FROM_RADIO_SIZE = 512 class StreamInterface(MeshInterface): """Interface class for meshtastic devices over a stream link (serial, TCP, etc)""" - def __init__(self, debugOut=None, noProto=False, connectNow=True): + def __init__(self, debugOut=None, noProto=False, connectNow=True, noNodes=False): """Constructor, opens a connection to self.stream Keyword Arguments: @@ -43,7 +43,7 @@ class StreamInterface(MeshInterface): # FIXME, figure out why daemon=True causes reader thread to exit too early self._rxThread = threading.Thread(target=self.__reader, args=(), daemon=True) - MeshInterface.__init__(self, debugOut=debugOut, noProto=noProto) + MeshInterface.__init__(self, debugOut=debugOut, noProto=noProto, noNodes=noNodes) # Start the reader thread after superclass constructor completes init if connectNow: diff --git a/meshtastic/tcp_interface.py b/meshtastic/tcp_interface.py index 4226306..d049dc4 100644 --- a/meshtastic/tcp_interface.py +++ b/meshtastic/tcp_interface.py @@ -17,6 +17,7 @@ class TCPInterface(StreamInterface): noProto=False, connectNow=True, portNumber=4403, + noNodes:bool=False, ): """Constructor, opens a connection to a specified IP address/hostname @@ -38,7 +39,7 @@ class TCPInterface(StreamInterface): self.socket = None StreamInterface.__init__( - self, debugOut=debugOut, noProto=noProto, connectNow=connectNow + self, debugOut=debugOut, noProto=noProto, connectNow=connectNow, noNodes=noNodes ) def _socket_shutdown(self):