diff --git a/meshtastic/__init__.py b/meshtastic/__init__.py index 7c21cab..b4695b0 100644 --- a/meshtastic/__init__.py +++ b/meshtastic/__init__.py @@ -91,18 +91,22 @@ format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20 """ OUR_APP_VERSION = 20200 + class ResponseHandler(NamedTuple): """A pending response callback, waiting for a response to one of our messages""" # requestId: int - used only as a key callback: Callable # FIXME, add timestamp and age out old requests + class KnownProtocol(NamedTuple): """Used to automatically decode known protocol payloads""" name: str # portnum: int, now a key - protobufFactory: Callable = None # If set, will be called to prase as a protocol buffer - onReceive: Callable = None # If set, invoked as onReceive(interface, packet) + # If set, will be called to prase as a protocol buffer + protobufFactory: Callable = None + # If set, invoked as onReceive(interface, packet) + onReceive: Callable = None class MeshInterface: @@ -125,8 +129,8 @@ class MeshInterface: self.nodes = None # FIXME self.isConnected = threading.Event() self.noProto = noProto - self.myInfo = None # We don't have device info yet - self.responseHandlers = {} # A map from request ID to the handler + self.myInfo = None # We don't have device info yet + self.responseHandlers = {} # A map from request ID to the handler random.seed() # FIXME, we should not clobber the random seedval here, instead tell user they must call it self.currentPacketId = random.randint(0, 0xffffffff) self._startConfig() @@ -141,7 +145,7 @@ class MeshInterface: if traceback is not None: logging.error(f'Traceback: {traceback}') self.close() - + def sendText(self, text: AnyStr, destinationId=BROADCAST_ADDR, wantAck=False, @@ -552,9 +556,10 @@ class MeshInterface: # decode position protobufs and update nodedb, provide decoded version as "position" in the published msg # move the following into a 'decoders' API that clients could register? - portNumInt = meshPacket.decoded.portnum # we want portnum as an int + portNumInt = meshPacket.decoded.portnum # we want portnum as an int handler = protocols.get(portNumInt) - p = None # The decoded protobuf as a dictionary (if we understand this message) + # The decoded protobuf as a dictionary (if we understand this message) + p = None if handler is not None: topic = f"meshtastic.receive.{handler.name}" @@ -573,7 +578,7 @@ class MeshInterface: # We ignore ACK packets, but send NAKs and data responses to the handlers requestId = asDict["decoded"].get("requestId") if requestId is not None: - pass + fixme("implment") logging.debug(f"Publishing topic {topic}") catchAndIgnore(f"publishing {topic}", lambda: pub.sendMessage( @@ -867,6 +872,7 @@ def _onTextReceive(iface, asDict): except Exception as ex: logging.error(f"Malformatted utf8 in text message: {ex}") + def _onPositionReceive(iface, asDict): """Special auto parsing for received messages""" p = asDict["decoded"]["position"] @@ -874,6 +880,7 @@ def _onPositionReceive(iface, asDict): # update node DB as needed iface._getOrCreateByNum(asDict["from"])["position"] = p + def _onNodeInfoReceive(iface, asDict): """Special auto parsing for received messages""" p = asDict["decoded"]["user"] @@ -893,5 +900,6 @@ protocols = { portnums_pb2.PortNum.ADMIN_APP: KnownProtocol("admin", admin_pb2.AdminMessage), portnums_pb2.PortNum.ROUTING_APP: KnownProtocol("routing", mesh_pb2.Routing), portnums_pb2.PortNum.ENVIRONMENTAL_MEASUREMENT_APP: KnownProtocol("environmental", environmental_measurement_pb2.EnvironmentalMeasurement), - portnums_pb2.PortNum.REMOTE_HARDWARE_APP: KnownProtocol("remotehw", remote_hardware_pb2.HardwareMessage) + portnums_pb2.PortNum.REMOTE_HARDWARE_APP: KnownProtocol( + "remotehw", remote_hardware_pb2.HardwareMessage) } diff --git a/meshtastic/test.py b/meshtastic/test.py index c81c085..0eb8747 100644 --- a/meshtastic/test.py +++ b/meshtastic/test.py @@ -19,6 +19,7 @@ testNumber = 0 sendingInterface = None + def onReceive(packet, interface): """Callback invoked when a packet arrives""" if sendingInterface == interface: @@ -31,6 +32,7 @@ def onReceive(packet, interface): # We only care a about clear text packets receivedPackets.append(p) + def onNode(node): """Callback invoked when the node DB changes""" print(f"Node changed: {node}") @@ -63,7 +65,7 @@ def testSend(fromInterface, toInterface, isBroadcast=False, asBinary=False): toNode = toInterface.myInfo.my_node_num logging.info(f"Sending test packet from {fromNode} to {toNode}") - wantAck = False # Don't want any sort of reliaible sending + wantAck = False # Don't want any sort of reliaible sending global sendingInterface sendingInterface = fromInterface if not asBinary: @@ -71,11 +73,11 @@ def testSend(fromInterface, toInterface, isBroadcast=False, asBinary=False): else: fromInterface.sendData((f"Binary {testNumber}").encode( "utf-8"), toNode, wantAck=wantAck) - for sec in range(45): # max of 45 secs before we timeout + for sec in range(45): # max of 45 secs before we timeout time.sleep(1) if (len(receivedPackets) >= 1): return True - return False # Failed to send + return False # Failed to send def testThread(numTests=50): @@ -88,14 +90,15 @@ def testThread(numTests=50): isBroadcast = True # asBinary=(i % 2 == 0) success = testSend( - interfaces[0], interfaces[1], isBroadcast, asBinary = False) + interfaces[0], interfaces[1], isBroadcast, asBinary=False) if not success: numFail = numFail + 1 logging.error( f"Test failed, expected packet not received ({numFail} failures so far)") else: numSuccess = numSuccess + 1 - logging.info(f"Test succeeded ({numSuccess} successes ({numFail} failures) so far)") + logging.info( + f"Test succeeded ({numSuccess} successes ({numFail} failures) so far)") if numFail >= 3: for i in interfaces: @@ -109,11 +112,13 @@ def onConnection(topic=pub.AUTO_TOPIC): """Callback invoked when we connect/disconnect from a radio""" print(f"Connection changed: {topic.getName()}") + def openDebugLog(portName): debugname = "log" + portName.replace("/", "_") logging.info(f"Writing serial debugging to {debugname}") return open(debugname, 'w+', buffering=1) + def testAll(): """ Run a series of tests using devices we can find. @@ -136,4 +141,3 @@ def testAll(): for i in interfaces: i.close() - diff --git a/meshtastic/util.py b/meshtastic/util.py index 8a1465a..a20d0ed 100644 --- a/meshtastic/util.py +++ b/meshtastic/util.py @@ -18,6 +18,7 @@ def catchAndIgnore(reason, closure): except BaseException as ex: logging.error(f"Exception thrown in {reason}: {ex}") + def findPorts(): """Find all ports that might have meshtastic devices