From 380cf4c999090527ed84fd48fd8923702b23b25a Mon Sep 17 00:00:00 2001 From: geeksville Date: Tue, 28 Apr 2020 09:55:22 -0700 Subject: [PATCH] dynamically probe for devices --- TODO.md | 11 +++++++++++ meshtastic/__main__.py | 9 ++++++--- meshtastic/interface.py | 23 +++++++++++++++++------ setup.py | 2 +- 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/TODO.md b/TODO.md index 6e1da68..8cd10d2 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,16 @@ # TODO +## Before initial release + +- make pubsub work +- make docs decent +- document properties/fields +- include examples in readme. hello.py, textchat.py, replymessage.py +- DONE use port enumeration to find ports https://pyserial.readthedocs.io/en/latest/shortintro.html +- DONE make serial debug output optional (by providing a null stream) + +## Eventual + - possibly use tk to make a multiwindow test console: https://stackoverflow.com/questions/12351786/how-to-redirect-print-statements-to-tkinter-text-widget ## Primary API: MeshInterface diff --git a/meshtastic/__main__.py b/meshtastic/__main__.py index b541af1..5d59436 100644 --- a/meshtastic/__main__.py +++ b/meshtastic/__main__.py @@ -10,16 +10,19 @@ def main(): """Perform command line meshtastic operations""" parser = argparse.ArgumentParser() + parser.add_argument( + "--device", + help="The port the Meshtastic device is connected to, i.e. /dev/ttyUSB0. If unspecified, we'll try to find it.", + default=None) + parser.add_argument("--debug", help="Show debug log message", action="store_true") args = parser.parse_args() logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO) - client = StreamInterface("/dev/ttyUSB0") + client = StreamInterface(args.device) -# self.sendText("hello world") - if __name__ == "__main__": main() diff --git a/meshtastic/interface.py b/meshtastic/interface.py index 306bbd1..dea26c7 100644 --- a/meshtastic/interface.py +++ b/meshtastic/interface.py @@ -1,5 +1,6 @@ import serial +import serial.tools.list_ports import threading import logging import sys @@ -16,8 +17,6 @@ BROADCAST_ADDR = "all" # A special ID that means broadcast """ TODO: -* use port enumeration to find ports https://pyserial.readthedocs.io/en/latest/shortintro.html - Contains a reader thread that is always trying to read on the serial port. @@ -49,9 +48,9 @@ MY_CONFIG_ID = 42 class MeshInterface: """Interface class for meshtastic devices""" - def __init__(self): + def __init__(self, debugOut=sys.stdout): """Constructor""" - self.debugOut = sys.stdout + self.debugOut = debugOut self.nodes = None # FIXME self._startConfig() @@ -117,8 +116,20 @@ class MeshInterface: class StreamInterface(MeshInterface): """Interface class for meshtastic devices over a stream link(serial, TCP, etc)""" - def __init__(self, devPath): - """Constructor, opens a connection to a specified serial port""" + def __init__(self, devPath=None, debugOut=sys.stdout): + """Constructor, opens a connection to a specified serial port, or if unspecified try to find one Meshtastic device by probing""" + + if devPath is None: + ports = list(filter(lambda port: port.vid != None, + serial.tools.list_ports.comports())) + if len(ports) == 0: + raise Exception("No Meshtastic devices detected") + elif len(ports) > 1: + raise Exception( + f"Multiple ports detected, you must specify a device, such as {ports[0].device}") + else: + devPath = ports[0].device + logging.debug(f"Connecting to {devPath}") self._rxBuf = bytes() # empty self._wantExit = False diff --git a/setup.py b/setup.py index 7a39101..a25ca04 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ setup( ], packages=["meshtastic"], include_package_data=True, - install_requires=["pyserial"], + install_requires=["pyserial>=3.4"], python_requires='>=3', entry_points={ "console_scripts": [