Skip to content

Commit bdf3a24

Browse files
authored
Merge pull request #546 from ianmcorvidae/request-position
Add a `--request-position` argument to request positions from nodes
2 parents 948846e + e8ba558 commit bdf3a24

File tree

3 files changed

+72
-7
lines changed

3 files changed

+72
-7
lines changed

meshtastic/__main__.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,13 @@ def onConnected(interface):
435435
print(f"Sending telemetry request to {args.dest} (this could take a while)")
436436
interface.sendTelemetry(destinationId=args.dest, wantResponse=True)
437437

438+
if args.request_position:
439+
if args.dest == BROADCAST_ADDR:
440+
meshtastic.util.our_exit("Warning: Must use a destination node ID.")
441+
else:
442+
print(f"Sending position request to {args.dest} (this could take a while)")
443+
interface.sendPosition(destinationId=args.dest, wantResponse=True)
444+
438445
if args.gpio_wrb or args.gpio_rd or args.gpio_watch:
439446
if args.dest == BROADCAST_ADDR:
440447
meshtastic.util.our_exit("Warning: Must use a destination node ID.")
@@ -1299,7 +1306,15 @@ def initParser():
12991306
group.add_argument(
13001307
"--request-telemetry",
13011308
help="Request telemetry from a node. "
1302-
"You need pass the destination ID as argument with '--dest'. "
1309+
"You need to pass the destination ID as argument with '--dest'. "
1310+
"For repeaters, the nodeNum is required.",
1311+
action="store_true",
1312+
)
1313+
1314+
group.add_argument(
1315+
"--request-position",
1316+
help="Request the position from a nade. "
1317+
"You need to pass the destination ID as an argument with '--dest'. "
13031318
"For repeaters, the nodeNum is required.",
13041319
action="store_true",
13051320
)

meshtastic/mesh_interface.py

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -381,13 +381,50 @@ def sendPosition(
381381
p.time = timeSec
382382
logging.debug(f"p.time:{p.time}")
383383

384-
return self.sendData(
384+
if wantResponse:
385+
onResponse = self.onResponsePosition
386+
else:
387+
onResponse = None
388+
389+
d = self.sendData(
385390
p,
386391
destinationId,
387392
portNum=portnums_pb2.PortNum.POSITION_APP,
388393
wantAck=wantAck,
389394
wantResponse=wantResponse,
395+
onResponse=onResponse,
390396
)
397+
if wantResponse:
398+
self.waitForPosition()
399+
return d
400+
401+
def onResponsePosition(self, p):
402+
"""on response for position"""
403+
if p["decoded"]["portnum"] == 'POSITION_APP':
404+
self._acknowledgment.receivedPosition = True
405+
position = mesh_pb2.Position()
406+
position.ParseFromString(p["decoded"]["payload"])
407+
408+
ret = "Position received: "
409+
if position.latitude_i != 0 and position.longitude_i != 0:
410+
ret += f"({position.latitude_i * 10**-7}, {position.longitude_i * 10**-7})"
411+
else:
412+
ret += "(unknown)"
413+
if position.altitude != 0:
414+
ret += f" {position.altitude}m"
415+
416+
if position.precision_bits not in [0,32]:
417+
ret += f" precision:{position.precision_bits}"
418+
elif position.precision_bits == 32:
419+
ret += " full precision"
420+
elif position.precision_bits == 0:
421+
ret += " position disabled"
422+
423+
print(ret)
424+
425+
elif p["decoded"]["portnum"] == 'ROUTING_APP':
426+
if p["decoded"]["routing"]["errorReason"] == 'NO_RESPONSE':
427+
our_exit("No response from node. At least firmware 2.1.22 is required on the destination node.")
391428

392429
def sendTraceRoute(self, dest: Union[int, str], hopLimit: int):
393430
"""Send the trace route"""
@@ -445,11 +482,6 @@ def sendTelemetry(self, destinationId=BROADCAST_ADDR, wantResponse=False):
445482
else:
446483
onResponse = None
447484

448-
if destinationId.startswith("!"):
449-
destinationId = int(destinationId[1:], 16)
450-
else:
451-
destinationId = int(destinationId)
452-
453485
self.sendData(
454486
r,
455487
destinationId=destinationId,
@@ -573,6 +605,12 @@ def waitForTelemetry(self):
573605
if not success:
574606
raise MeshInterface.MeshInterfaceError("Timed out waiting for telemetry")
575607

608+
def waitForPosition(self):
609+
"""Wait for position"""
610+
success = self._timeout.waitForPosition(self._acknowledgment)
611+
if not success:
612+
raise MeshInterface.MeshInterfaceError("Timed out waiting for position")
613+
576614
def getMyNodeInfo(self) -> Optional[Dict]:
577615
"""Get info about my node."""
578616
if self.myInfo is None or self.nodesByNum is None:

meshtastic/util.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,16 @@ def waitForTelemetry(self, acknowledgment) -> bool:
206206
time.sleep(self.sleepInterval)
207207
return False
208208

209+
def waitForPosition(self, acknowledgment) -> bool:
210+
"""Block until position response is received. Returns True if position response has been received."""
211+
self.reset()
212+
while time.time() < self.expireTime:
213+
if getattr(acknowledgment, "receivedPosition", None):
214+
acknowledgment.reset()
215+
return True
216+
time.sleep(self.sleepInterval)
217+
return False
218+
209219
class Acknowledgment:
210220
"A class that records which type of acknowledgment was just received, if any."
211221

@@ -216,6 +226,7 @@ def __init__(self):
216226
self.receivedImplAck = False
217227
self.receivedTraceRoute = False
218228
self.receivedTelemetry = False
229+
self.receivedPosition = False
219230

220231
def reset(self):
221232
"""reset"""
@@ -224,6 +235,7 @@ def reset(self):
224235
self.receivedImplAck = False
225236
self.receivedTraceRoute = False
226237
self.receivedTelemetry = False
238+
self.receivedPosition = False
227239

228240

229241
class DeferredExecution:

0 commit comments

Comments
 (0)