Compare commits

...

10 Commits
2.0.5 ... 2.0.6

Author SHA1 Message Date
Thomas Göttgens
57719ddd5e Merge pull request #407 from GUVWAF/traceRoute
Traceroute option
2022-12-06 15:36:49 +01:00
GUVWAF
d0b8b9ff1b Forgot to convert into TRACEROUTE_APP 2022-12-06 14:18:30 +01:00
github-actions
c5c9723208 Update protobuf submodule 2022-12-06 13:16:28 +00:00
Ben Meadors
9bceaafd9c Merge pull request #406 from GUVWAF/hopLimit
Set hopLimit to the config of the device
2022-12-05 20:10:27 -06:00
GUVWAF
7d3a9178ea Add traceroute option 2022-12-05 20:36:34 +01:00
GUVWAF
2c76c0cafa Remove setting hopLimit to default
Instead set is to config of device
2022-12-05 20:04:38 +01:00
GUVWAF
82977e9ef2 Fix --ch-set help message 2022-12-05 20:02:53 +01:00
Sacha Weatherstone
7a9c25da8e Merge pull request #404 from ahmedkadd/fix-script-typo
Rename protobufs shell script to fix typo
2022-12-02 14:39:18 +11:00
Ahmed Kaddoura
342c48fb16 Rename protobufs shell script to fix typo 2022-11-30 07:58:56 -08:00
github-actions
6bc955a403 bump version 2022-11-27 12:10:59 +00:00
11 changed files with 157 additions and 110 deletions

View File

@@ -183,5 +183,6 @@ protocols = {
portnums_pb2.PortNum.ROUTING_APP: KnownProtocol("routing", mesh_pb2.Routing), portnums_pb2.PortNum.ROUTING_APP: KnownProtocol("routing", mesh_pb2.Routing),
portnums_pb2.PortNum.TELEMETRY_APP: KnownProtocol("telemetry", telemetry_pb2.Telemetry), portnums_pb2.PortNum.TELEMETRY_APP: KnownProtocol("telemetry", telemetry_pb2.Telemetry),
portnums_pb2.PortNum.REMOTE_HARDWARE_APP: KnownProtocol("remotehw", remote_hardware_pb2.HardwareMessage), portnums_pb2.PortNum.REMOTE_HARDWARE_APP: KnownProtocol("remotehw", remote_hardware_pb2.HardwareMessage),
portnums_pb2.PortNum.SIMULATOR_APP: KnownProtocol("simulator", mesh_pb2.Compressed) portnums_pb2.PortNum.SIMULATOR_APP: KnownProtocol("simulator", mesh_pb2.Compressed),
portnums_pb2.PortNum.TRACEROUTE_APP: KnownProtocol("traceroute", mesh_pb2.RouteDiscovery)
} }

View File

@@ -330,6 +330,13 @@ def onConnected(interface):
interface.sendData(payload, args.dest, portNum=portnums_pb2.PortNum.REPLY_APP, interface.sendData(payload, args.dest, portNum=portnums_pb2.PortNum.REPLY_APP,
wantAck=True, wantResponse=True) wantAck=True, wantResponse=True)
if args.traceroute:
loraConfig = getattr(interface.localNode.localConfig, 'lora')
hopLimit = getattr(loraConfig, 'hop_limit')
dest = str(args.traceroute)
print(f"Sending traceroute request to {dest} (this could take a while)")
interface.sendTraceRoute(dest, hopLimit)
if args.gpio_wrb or args.gpio_rd or args.gpio_watch: if args.gpio_wrb or args.gpio_rd or args.gpio_watch:
if args.dest == BROADCAST_ADDR: if args.dest == BROADCAST_ADDR:
meshtastic.util.our_exit("Warning: Must use a destination node ID.") meshtastic.util.our_exit("Warning: Must use a destination node ID.")
@@ -889,7 +896,7 @@ def initParser():
"--ch-set", help=("Set a channel parameter. To see channel settings available:'--ch-set all all --ch-index 0'. " "--ch-set", help=("Set a channel parameter. To see channel settings available:'--ch-set all all --ch-index 0'. "
"Can set the 'psk' using this command. To disable encryption on primary channel:'--ch-set psk none --ch-index 0'. " "Can set the 'psk' using this command. To disable encryption on primary channel:'--ch-set psk none --ch-index 0'. "
"To set encryption with a new random key on second channel:'--ch-set psk random --ch-index 1'. " "To set encryption with a new random key on second channel:'--ch-set psk random --ch-index 1'. "
"To set encryption back to the default:'--ch-set default --ch-index 0'. To set encryption with your " "To set encryption back to the default:'--ch-set psk default --ch-index 0'. To set encryption with your "
"own key: '--ch-set psk 0x1a1a1a1a2b2b2b2b1a1a1a1a2b2b2b2b1a1a1a1a2b2b2b2b1a1a1a1a2b2b2b2b --ch-index 0'."), "own key: '--ch-set psk 0x1a1a1a1a2b2b2b2b1a1a1a1a2b2b2b2b1a1a1a1a2b2b2b2b1a1a1a1a2b2b2b2b --ch-index 0'."),
nargs=2, action='append') nargs=2, action='append')
@@ -935,6 +942,12 @@ def initParser():
parser.add_argument( parser.add_argument(
"--sendping", help="Send a ping message (which requests a reply)", action="store_true") "--sendping", help="Send a ping message (which requests a reply)", action="store_true")
parser.add_argument(
"--traceroute", help="Traceroute from connected node to a destination. " \
"You need pass the destination ID as argument, like " \
"this: '--traceroute !ba4bf9d0' " \
"Only nodes that have the encryption key can be traced.")
parser.add_argument( parser.add_argument(
"--reboot", help="Tell the destination node to reboot", action="store_true") "--reboot", help="Tell the destination node to reboot", action="store_true")

View File

File diff suppressed because one or more lines are too long

View File

@@ -53,7 +53,6 @@ class MeshInterface:
self.currentPacketId = random.randint(0, 0xffffffff) self.currentPacketId = random.randint(0, 0xffffffff)
self.nodesByNum = None self.nodesByNum = None
self.configId = None self.configId = None
self.defaultHopLimit = 3
self.gotResponse = False # used in gpio read self.gotResponse = False # used in gpio read
self.mask = None # used in gpio read and gpio watch self.mask = None # used in gpio read and gpio watch
@@ -176,7 +175,6 @@ class MeshInterface:
destinationId=BROADCAST_ADDR, destinationId=BROADCAST_ADDR,
wantAck=False, wantAck=False,
wantResponse=False, wantResponse=False,
hopLimit=None,
onResponse=None, onResponse=None,
channelIndex=0): channelIndex=0):
"""Send a utf8 string to some other node, if the node has a display it """Send a utf8 string to some other node, if the node has a display it
@@ -198,21 +196,17 @@ class MeshInterface:
Returns the sent packet. The id field will be populated in this packet Returns the sent packet. The id field will be populated in this packet
and can be used to track future message acks/naks. and can be used to track future message acks/naks.
""" """
if hopLimit is None:
hopLimit = self.defaultHopLimit
return self.sendData(text.encode("utf-8"), destinationId, return self.sendData(text.encode("utf-8"), destinationId,
portNum=portnums_pb2.PortNum.TEXT_MESSAGE_APP, portNum=portnums_pb2.PortNum.TEXT_MESSAGE_APP,
wantAck=wantAck, wantAck=wantAck,
wantResponse=wantResponse, wantResponse=wantResponse,
hopLimit=hopLimit,
onResponse=onResponse, onResponse=onResponse,
channelIndex=channelIndex) channelIndex=channelIndex)
def sendData(self, data, destinationId=BROADCAST_ADDR, def sendData(self, data, destinationId=BROADCAST_ADDR,
portNum=portnums_pb2.PortNum.PRIVATE_APP, wantAck=False, portNum=portnums_pb2.PortNum.PRIVATE_APP, wantAck=False,
wantResponse=False, wantResponse=False,
hopLimit=None,
onResponse=None, onResponse=None,
channelIndex=0): channelIndex=0):
"""Send a data packet to some other node """Send a data packet to some other node
@@ -237,8 +231,6 @@ class MeshInterface:
Returns the sent packet. The id field will be populated in this packet Returns the sent packet. The id field will be populated in this packet
and can be used to track future message acks/naks. and can be used to track future message acks/naks.
""" """
if hopLimit is None:
hopLimit = self.defaultHopLimit
if getattr(data, "SerializeToString", None): if getattr(data, "SerializeToString", None):
logging.debug(f"Serializing protobuf as data: {stripnl(data)}") logging.debug(f"Serializing protobuf as data: {stripnl(data)}")
@@ -261,8 +253,7 @@ class MeshInterface:
if onResponse is not None: if onResponse is not None:
self._addResponseHandler(meshPacket.id, onResponse) self._addResponseHandler(meshPacket.id, onResponse)
p = self._sendPacket(meshPacket, destinationId, p = self._sendPacket(meshPacket, destinationId, wantAck=wantAck)
wantAck=wantAck, hopLimit=hopLimit)
return p return p
def sendPosition(self, latitude=0.0, longitude=0.0, altitude=0, timeSec=0, def sendPosition(self, latitude=0.0, longitude=0.0, altitude=0, timeSec=0,
@@ -301,20 +292,41 @@ class MeshInterface:
wantAck=wantAck, wantAck=wantAck,
wantResponse=wantResponse) wantResponse=wantResponse)
def sendTraceRoute(self, dest, hopLimit):
r = mesh_pb2.RouteDiscovery()
self.sendData(r, destinationId=dest, portNum=portnums_pb2.PortNum.TRACEROUTE_APP,
wantResponse=True, onResponse=self.onResponseTraceRoute)
# extend timeout based on number of nodes, limit by configured hopLimit
waitFactor = min(len(self.nodes)-1, hopLimit)
self.waitForTraceRoute(waitFactor)
def onResponseTraceRoute(self, p):
routeDiscovery = mesh_pb2.RouteDiscovery()
routeDiscovery.ParseFromString(p["decoded"]["payload"])
asDict = google.protobuf.json_format.MessageToDict(routeDiscovery)
print("Route traced:")
routeStr = self._nodeNumToId(p["to"])
if "route" in asDict:
for nodeNum in asDict["route"]:
routeStr += " --> " + self._nodeNumToId(nodeNum)
routeStr += " --> " + self._nodeNumToId(p["from"])
print(routeStr)
self._acknowledgment.receivedTraceRoute = True
def _addResponseHandler(self, requestId, callback): def _addResponseHandler(self, requestId, callback):
self.responseHandlers[requestId] = ResponseHandler(callback) self.responseHandlers[requestId] = ResponseHandler(callback)
def _sendPacket(self, meshPacket, def _sendPacket(self, meshPacket,
destinationId=BROADCAST_ADDR, destinationId=BROADCAST_ADDR,
wantAck=False, hopLimit=None): wantAck=False):
"""Send a MeshPacket to the specified node (or if unspecified, broadcast). """Send a MeshPacket to the specified node (or if unspecified, broadcast).
You probably don't want this - use sendData instead. You probably don't want this - use sendData instead.
Returns the sent packet. The id field will be populated in this packet and Returns the sent packet. The id field will be populated in this packet and
can be used to track future message acks/naks. can be used to track future message acks/naks.
""" """
if hopLimit is None:
hopLimit = self.defaultHopLimit
# We allow users to talk to the local node before we've completed the full connection flow... # We allow users to talk to the local node before we've completed the full connection flow...
if(self.myInfo is not None and destinationId != self.myInfo.my_node_num): if(self.myInfo is not None and destinationId != self.myInfo.my_node_num):
@@ -348,6 +360,8 @@ class MeshInterface:
meshPacket.to = nodeNum meshPacket.to = nodeNum
meshPacket.want_ack = wantAck meshPacket.want_ack = wantAck
loraConfig = getattr(self.localNode.localConfig, 'lora')
hopLimit = getattr(loraConfig, 'hop_limit')
meshPacket.hop_limit = hopLimit meshPacket.hop_limit = hopLimit
# if the user hasn't set an ID for this packet (likely and recommended), # if the user hasn't set an ID for this packet (likely and recommended),
@@ -374,6 +388,11 @@ class MeshInterface:
if not success: if not success:
raise Exception("Timed out waiting for an acknowledgment") raise Exception("Timed out waiting for an acknowledgment")
def waitForTraceRoute(self, waitFactor):
success = self._timeout.waitForTraceRoute(waitFactor, self._acknowledgment)
if not success:
raise Exception("Timed out waiting for traceroute")
def getMyNodeInfo(self): def getMyNodeInfo(self):
"""Get info about my node.""" """Get info about my node."""
if self.myInfo is None: if self.myInfo is None:

View File

File diff suppressed because one or more lines are too long

View File

File diff suppressed because one or more lines are too long

View File

@@ -15,7 +15,7 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0eportnums.proto*\x90\x03\n\x07PortNum\x12\x0f\n\x0bUNKNOWN_APP\x10\x00\x12\x14\n\x10TEXT_MESSAGE_APP\x10\x01\x12\x17\n\x13REMOTE_HARDWARE_APP\x10\x02\x12\x10\n\x0cPOSITION_APP\x10\x03\x12\x10\n\x0cNODEINFO_APP\x10\x04\x12\x0f\n\x0bROUTING_APP\x10\x05\x12\r\n\tADMIN_APP\x10\x06\x12\x1f\n\x1bTEXT_MESSAGE_COMPRESSED_APP\x10\x07\x12\x10\n\x0cWAYPOINT_APP\x10\x08\x12\r\n\tAUDIO_APP\x10\t\x12\r\n\tREPLY_APP\x10 \x12\x11\n\rIP_TUNNEL_APP\x10!\x12\x0e\n\nSERIAL_APP\x10@\x12\x15\n\x11STORE_FORWARD_APP\x10\x41\x12\x12\n\x0eRANGE_TEST_APP\x10\x42\x12\x11\n\rTELEMETRY_APP\x10\x43\x12\x0b\n\x07ZPS_APP\x10\x44\x12\x11\n\rSIMULATOR_APP\x10\x45\x12\x10\n\x0bPRIVATE_APP\x10\x80\x02\x12\x13\n\x0e\x41TAK_FORWARDER\x10\x81\x02\x12\x08\n\x03MAX\x10\xff\x03\x42\x45\n\x13\x63om.geeksville.meshB\x08PortnumsH\x03Z\"github.com/meshtastic/go/generatedb\x06proto3') DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0eportnums.proto*\xa4\x03\n\x07PortNum\x12\x0f\n\x0bUNKNOWN_APP\x10\x00\x12\x14\n\x10TEXT_MESSAGE_APP\x10\x01\x12\x17\n\x13REMOTE_HARDWARE_APP\x10\x02\x12\x10\n\x0cPOSITION_APP\x10\x03\x12\x10\n\x0cNODEINFO_APP\x10\x04\x12\x0f\n\x0bROUTING_APP\x10\x05\x12\r\n\tADMIN_APP\x10\x06\x12\x1f\n\x1bTEXT_MESSAGE_COMPRESSED_APP\x10\x07\x12\x10\n\x0cWAYPOINT_APP\x10\x08\x12\r\n\tAUDIO_APP\x10\t\x12\r\n\tREPLY_APP\x10 \x12\x11\n\rIP_TUNNEL_APP\x10!\x12\x0e\n\nSERIAL_APP\x10@\x12\x15\n\x11STORE_FORWARD_APP\x10\x41\x12\x12\n\x0eRANGE_TEST_APP\x10\x42\x12\x11\n\rTELEMETRY_APP\x10\x43\x12\x0b\n\x07ZPS_APP\x10\x44\x12\x11\n\rSIMULATOR_APP\x10\x45\x12\x12\n\x0eTRACEROUTE_APP\x10\x46\x12\x10\n\x0bPRIVATE_APP\x10\x80\x02\x12\x13\n\x0e\x41TAK_FORWARDER\x10\x81\x02\x12\x08\n\x03MAX\x10\xff\x03\x42\x45\n\x13\x63om.geeksville.meshB\x08PortnumsH\x03Z\"github.com/meshtastic/go/generatedb\x06proto3')
_PORTNUM = DESCRIPTOR.enum_types_by_name['PortNum'] _PORTNUM = DESCRIPTOR.enum_types_by_name['PortNum']
PortNum = enum_type_wrapper.EnumTypeWrapper(_PORTNUM) PortNum = enum_type_wrapper.EnumTypeWrapper(_PORTNUM)
@@ -37,6 +37,7 @@ RANGE_TEST_APP = 66
TELEMETRY_APP = 67 TELEMETRY_APP = 67
ZPS_APP = 68 ZPS_APP = 68
SIMULATOR_APP = 69 SIMULATOR_APP = 69
TRACEROUTE_APP = 70
PRIVATE_APP = 256 PRIVATE_APP = 256
ATAK_FORWARDER = 257 ATAK_FORWARDER = 257
MAX = 511 MAX = 511
@@ -47,5 +48,5 @@ if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\010PortnumsH\003Z\"github.com/meshtastic/go/generated' DESCRIPTOR._serialized_options = b'\n\023com.geeksville.meshB\010PortnumsH\003Z\"github.com/meshtastic/go/generated'
_PORTNUM._serialized_start=19 _PORTNUM._serialized_start=19
_PORTNUM._serialized_end=419 _PORTNUM._serialized_end=439
# @@protoc_insertion_point(module_scope) # @@protoc_insertion_point(module_scope)

View File

@@ -169,17 +169,30 @@ class Timeout:
time.sleep(self.sleepInterval) time.sleep(self.sleepInterval)
return False return False
def waitForTraceRoute(self, waitFactor, acknowledgment, attr='receivedTraceRoute'):
"""Block until traceroute response is received. Returns True if traceroute response has been received."""
self.expireTimeout *= waitFactor
self.reset()
while time.time() < self.expireTime:
if getattr(acknowledgment, attr, None):
acknowledgment.reset()
return True
time.sleep(self.sleepInterval)
return False
class Acknowledgment: class Acknowledgment:
"A class that records which type of acknowledgment was just received, if any." "A class that records which type of acknowledgment was just received, if any."
def __init__(self): def __init__(self):
self.receivedAck = False self.receivedAck = False
self.receivedNak = False self.receivedNak = False
self.receivedImplAck = False self.receivedImplAck = False
self.receivedTraceRoute = False
def reset(self): def reset(self):
self.receivedAck = False self.receivedAck = False
self.receivedNak = False self.receivedNak = False
self.receivedImplAck = False self.receivedImplAck = False
self.receivedTraceRoute = False
class DeferredExecution(): class DeferredExecution():
"""A thread that accepts closures to run, and runs them as they are received""" """A thread that accepts closures to run, and runs them as they are received"""

View File

@@ -12,7 +12,7 @@ with open("README.md", "r") as fh:
# This call to setup() does all the work # This call to setup() does all the work
setup( setup(
name="meshtastic", name="meshtastic",
version="2.0.4", version="2.0.5",
description="Python API & client shell for talking to Meshtastic devices", description="Python API & client shell for talking to Meshtastic devices",
long_description=long_description, long_description=long_description,
long_description_content_type="text/markdown", long_description_content_type="text/markdown",