3737 message_to_json ,
3838)
3939
40+ from typing import Any , Callable , Dict , List , Optional , Union
41+
4042
4143class MeshInterface :
4244 """Interface class for meshtastic devices
@@ -54,35 +56,35 @@ def __init__(self, message):
5456 self .message = message
5557 super ().__init__ (self .message )
5658
57- def __init__ (self , debugOut = None , noProto = False ):
59+ def __init__ (self , debugOut = None , noProto : bool = False ) -> None :
5860 """Constructor
5961
6062 Keyword Arguments:
6163 noProto -- If True, don't try to run our protocol on the
6264 link - just be a dumb serial client.
6365 """
6466 self .debugOut = debugOut
65- self .nodes = None # FIXME
66- self .isConnected = threading .Event ()
67- self .noProto = noProto
68- self .localNode = meshtastic .node .Node (self , - 1 ) # We fixup nodenum later
69- self .myInfo = None # We don't have device info yet
70- self .metadata = None # We don't have device metadata yet
71- self .responseHandlers = {} # A map from request ID to the handler
67+ self .nodes : Optional [ Dict [ str , Dict ]] = None # FIXME
68+ self .isConnected : threading . Event = threading .Event ()
69+ self .noProto : bool = noProto
70+ self .localNode : meshtastic . node . Node = meshtastic .node .Node (self , - 1 ) # We fixup nodenum later
71+ self .myInfo : Optional [ mesh_pb2 . MyNodeInfo ] = None # We don't have device info yet
72+ self .metadata : Optional [ mesh_pb2 . DeviceMetadata ] = None # We don't have device metadata yet
73+ self .responseHandlers : Dict [ int , ResponseHandler ] = {} # A map from request ID to the handler
7274 self .failure = (
7375 None # If we've encountered a fatal exception it will be kept here
7476 )
75- self ._timeout = Timeout ()
76- self ._acknowledgment = Acknowledgment ()
77- self .heartbeatTimer = None
77+ self ._timeout : Timeout = Timeout ()
78+ self ._acknowledgment : Acknowledgment = Acknowledgment ()
79+ self .heartbeatTimer : Optional [ threading . Timer ] = None
7880 random .seed () # FIXME, we should not clobber the random seedval here, instead tell user they must call it
79- self .currentPacketId = random .randint (0 , 0xFFFFFFFF )
80- self .nodesByNum = None
81- self .configId = None
82- self .gotResponse = False # used in gpio read
83- self .mask = None # used in gpio read and gpio watch
84- self .queueStatus = None
85- self .queue = collections .OrderedDict ()
81+ self .currentPacketId : int = random .randint (0 , 0xFFFFFFFF )
82+ self .nodesByNum : Optional [ Dict [ int , Dict ]] = None
83+ self .configId : Optional [ int ] = None
84+ self .gotResponse : bool = False # used in gpio read
85+ self .mask : Optional [ int ] = None # used in gpio read and gpio watch
86+ self .queueStatus : Optional [ mesh_pb2 . QueueStatus ] = None
87+ self .queue : collections . OrderedDict = collections .OrderedDict ()
8688
8789 def close (self ):
8890 """Shutdown this interface"""
@@ -103,7 +105,7 @@ def __exit__(self, exc_type, exc_value, traceback):
103105 logging .error (f"Traceback: { traceback } " )
104106 self .close ()
105107
106- def showInfo (self , file = sys .stdout ): # pylint: disable=W0613
108+ def showInfo (self , file = sys .stdout ) -> str : # pylint: disable=W0613
107109 """Show human readable summary about this object"""
108110 owner = f"Owner: { self .getLongName ()} ({ self .getShortName ()} )"
109111 myinfo = ""
@@ -135,28 +137,28 @@ def showInfo(self, file=sys.stdout): # pylint: disable=W0613
135137 print (infos )
136138 return infos
137139
138- def showNodes (self , includeSelf = True , file = sys .stdout ): # pylint: disable=W0613
140+ def showNodes (self , includeSelf : bool = True , file = sys .stdout ) -> str : # pylint: disable=W0613
139141 """Show table summary of nodes in mesh"""
140142
141- def formatFloat (value , precision = 2 , unit = "" ):
143+ def formatFloat (value , precision = 2 , unit = "" ) -> Optional [ str ] :
142144 """Format a float value with precision."""
143145 return f"{ value :.{precision }f} { unit } " if value else None
144146
145- def getLH (ts ):
147+ def getLH (ts ) -> Optional [ str ] :
146148 """Format last heard"""
147149 return (
148150 datetime .fromtimestamp (ts ).strftime ("%Y-%m-%d %H:%M:%S" ) if ts else None
149151 )
150152
151- def getTimeAgo (ts ):
153+ def getTimeAgo (ts ) -> Optional [ str ] :
152154 """Format how long ago have we heard from this node (aka timeago)."""
153155 return (
154156 timeago .format (datetime .fromtimestamp (ts ), datetime .now ())
155157 if ts
156158 else None
157159 )
158160
159- rows = []
161+ rows : List [ Dict [ str , Any ]] = []
160162 if self .nodesByNum :
161163 logging .debug (f"self.nodes:{ self .nodes } " )
162164 for node in self .nodesByNum .values ():
@@ -225,7 +227,7 @@ def getTimeAgo(ts):
225227 print (table )
226228 return table
227229
228- def getNode (self , nodeId , requestChannels = True ):
230+ def getNode (self , nodeId : str , requestChannels : bool = True ) -> meshtastic . node . Node :
229231 """Return a node object which contains device settings and channel info"""
230232 if nodeId in (LOCAL_ADDR , BROADCAST_ADDR ):
231233 return self .localNode
@@ -242,11 +244,11 @@ def getNode(self, nodeId, requestChannels=True):
242244 def sendText (
243245 self ,
244246 text : str ,
245- destinationId = BROADCAST_ADDR ,
246- wantAck = False ,
247- wantResponse = False ,
248- onResponse = None ,
249- channelIndex = 0 ,
247+ destinationId : Union [ int , str ] = BROADCAST_ADDR ,
248+ wantAck : bool = False ,
249+ wantResponse : bool = False ,
250+ onResponse : Optional [ Callable [[ mesh_pb2 . MeshPacket ], Any ]] = None ,
251+ channelIndex : int = 0 ,
250252 ):
251253 """Send a utf8 string to some other node, if the node has a display it
252254 will also be shown on the device.
@@ -281,12 +283,12 @@ def sendText(
281283 def sendData (
282284 self ,
283285 data ,
284- destinationId = BROADCAST_ADDR ,
285- portNum = portnums_pb2 .PortNum .PRIVATE_APP ,
286- wantAck = False ,
287- wantResponse = False ,
288- onResponse = None ,
289- channelIndex = 0 ,
286+ destinationId : Union [ int , str ] = BROADCAST_ADDR ,
287+ portNum : portnums_pb2 . PortNum . ValueType = portnums_pb2 .PortNum .PRIVATE_APP ,
288+ wantAck : bool = False ,
289+ wantResponse : bool = False ,
290+ onResponse : Optional [ Callable [[ mesh_pb2 . MeshPacket ], Any ]] = None ,
291+ channelIndex : int = 0 ,
290292 ):
291293 """Send a data packet to some other node
292294
@@ -341,13 +343,13 @@ def sendData(
341343
342344 def sendPosition (
343345 self ,
344- latitude = 0.0 ,
345- longitude = 0.0 ,
346- altitude = 0 ,
347- timeSec = 0 ,
348- destinationId = BROADCAST_ADDR ,
349- wantAck = False ,
350- wantResponse = False ,
346+ latitude : float = 0.0 ,
347+ longitude : float = 0.0 ,
348+ altitude : int = 0 ,
349+ timeSec : int = 0 ,
350+ destinationId : Union [ int , str ] = BROADCAST_ADDR ,
351+ wantAck : bool = False ,
352+ wantResponse : bool = False ,
351353 ):
352354 """
353355 Send a position packet to some other node (normally a broadcast)
@@ -374,8 +376,8 @@ def sendPosition(
374376 logging .debug (f"p.altitude:{ p .altitude } " )
375377
376378 if timeSec == 0 :
377- timeSec = time .time () # returns unix timestamp in seconds
378- p .time = int ( timeSec )
379+ timeSec = int ( time .time () ) # returns unix timestamp in seconds
380+ p .time = timeSec
379381 logging .debug (f"p.time:{ p .time } " )
380382
381383 return self .sendData (
@@ -386,7 +388,7 @@ def sendPosition(
386388 wantResponse = wantResponse ,
387389 )
388390
389- def sendTraceRoute (self , dest , hopLimit ):
391+ def sendTraceRoute (self , dest : Union [ int , str ], hopLimit : int ):
390392 """Send the trace route"""
391393 r = mesh_pb2 .RouteDiscovery ()
392394 self .sendData (
@@ -397,7 +399,7 @@ def sendTraceRoute(self, dest, hopLimit):
397399 onResponse = self .onResponseTraceRoute ,
398400 )
399401 # extend timeout based on number of nodes, limit by configured hopLimit
400- waitFactor = min (len (self .nodes ) - 1 , hopLimit )
402+ waitFactor = min (len (self .nodes ) - 1 if self . nodes else 0 , hopLimit )
401403 self .waitForTraceRoute (waitFactor )
402404
403405 def onResponseTraceRoute (self , p ):
@@ -480,10 +482,10 @@ def onResponseTelemetry(self, p):
480482 if p ["decoded" ]["routing" ]["errorReason" ] == 'NO_RESPONSE' :
481483 our_exit ("No response from node. At least firmware 2.1.22 is required on the destination node." )
482484
483- def _addResponseHandler (self , requestId , callback ):
485+ def _addResponseHandler (self , requestId : int , callback : Callable ):
484486 self .responseHandlers [requestId ] = ResponseHandler (callback )
485487
486- def _sendPacket (self , meshPacket , destinationId = BROADCAST_ADDR , wantAck = False ):
488+ def _sendPacket (self , meshPacket : mesh_pb2 . MeshPacket , destinationId : Union [ int , str ] = BROADCAST_ADDR , wantAck : bool = False ):
487489 """Send a MeshPacket to the specified node (or if unspecified, broadcast).
488490 You probably don't want this - use sendData instead.
489491
@@ -497,7 +499,7 @@ def _sendPacket(self, meshPacket, destinationId=BROADCAST_ADDR, wantAck=False):
497499
498500 toRadio = mesh_pb2 .ToRadio ()
499501
500- nodeNum = 0
502+ nodeNum : int = 0
501503 if destinationId is None :
502504 our_exit ("Warning: destinationId must not be None" )
503505 elif isinstance (destinationId , int ):
@@ -515,9 +517,10 @@ def _sendPacket(self, meshPacket, destinationId=BROADCAST_ADDR, wantAck=False):
515517 else :
516518 if self .nodes :
517519 node = self .nodes .get (destinationId )
518- if not node :
520+ if node is None :
519521 our_exit (f"Warning: NodeId { destinationId } not found in DB" )
520- nodeNum = node ["num" ]
522+ else :
523+ nodeNum = node ["num" ]
521524 else :
522525 logging .warning ("Warning: There were no self.nodes." )
523526
@@ -569,9 +572,9 @@ def waitForTelemetry(self):
569572 if not success :
570573 raise MeshInterface .MeshInterfaceError ("Timed out waiting for telemetry" )
571574
572- def getMyNodeInfo (self ):
575+ def getMyNodeInfo (self ) -> Optional [ Dict ] :
573576 """Get info about my node."""
574- if self .myInfo is None :
577+ if self .myInfo is None or self . nodesByNum is None :
575578 return None
576579 logging .debug (f"self.nodesByNum:{ self .nodesByNum } " )
577580 return self .nodesByNum .get (self .myInfo .my_node_num )
@@ -608,7 +611,7 @@ def _waitConnected(self, timeout=30.0):
608611 if self .failure :
609612 raise self .failure
610613
611- def _generatePacketId (self ):
614+ def _generatePacketId (self ) -> int :
612615 """Get a new unique packet ID"""
613616 if self .currentPacketId is None :
614617 raise MeshInterface .MeshInterfaceError ("Not connected yet, can not generate packet" )
@@ -670,18 +673,18 @@ def _sendDisconnect(self):
670673 m .disconnect = True
671674 self ._sendToRadio (m )
672675
673- def _queueHasFreeSpace (self ):
676+ def _queueHasFreeSpace (self ) -> bool :
674677 # We never got queueStatus, maybe the firmware is old
675678 if self .queueStatus is None :
676679 return True
677680 return self .queueStatus .free > 0
678681
679- def _queueClaim (self ):
682+ def _queueClaim (self ) -> None :
680683 if self .queueStatus is None :
681684 return
682685 self .queueStatus .free -= 1
683686
684- def _sendToRadio (self , toRadio ) :
687+ def _sendToRadio (self , toRadio : mesh_pb2 . ToRadio ) -> None :
685688 """Send a ToRadio protobuf to the device"""
686689 if self .noProto :
687690 logging .warning (
@@ -730,18 +733,18 @@ def _sendToRadio(self, toRadio):
730733 self .queue [packetId ] = packet
731734 # logging.warn("queue + resentQueue: " + " ".join(f'{k:08x}' for k in self.queue))
732735
733- def _sendToRadioImpl (self , toRadio ) :
736+ def _sendToRadioImpl (self , toRadio : mesh_pb2 . ToRadio ) -> None :
734737 """Send a ToRadio protobuf to the device"""
735738 logging .error (f"Subclass must provide toradio: { toRadio } " )
736739
737- def _handleConfigComplete (self ):
740+ def _handleConfigComplete (self ) -> None :
738741 """
739742 Done with initial config messages, now send regular MeshPackets
740743 to ask for settings and channels
741744 """
742745 self .localNode .requestChannels ()
743746
744- def _handleQueueStatusFromRadio (self , queueStatus ):
747+ def _handleQueueStatusFromRadio (self , queueStatus ) -> None :
745748 self .queueStatus = queueStatus
746749 logging .debug (
747750 f"TX QUEUE free { queueStatus .free } of { queueStatus .maxlen } , res = { queueStatus .res } , id = { queueStatus .mesh_packet_id :08x} "
@@ -892,7 +895,7 @@ def _handleFromRadio(self, fromRadioBytes):
892895 else :
893896 logging .debug ("Unexpected FromRadio payload" )
894897
895- def _fixupPosition (self , position ) :
898+ def _fixupPosition (self , position : Dict ) -> Dict :
896899 """Convert integer lat/lon into floats
897900
898901 Arguments:
0 commit comments