Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion meshtastic/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,13 @@ def onConnected(interface):
print(f"Sending telemetry request to {args.dest} (this could take a while)")
interface.sendTelemetry(destinationId=args.dest, wantResponse=True)

if args.request_position:
if args.dest == BROADCAST_ADDR:
meshtastic.util.our_exit("Warning: Must use a destination node ID.")
else:
print(f"Sending position request to {args.dest} (this could take a while)")
interface.sendPosition(destinationId=args.dest, wantResponse=True)

if args.gpio_wrb or args.gpio_rd or args.gpio_watch:
if args.dest == BROADCAST_ADDR:
meshtastic.util.our_exit("Warning: Must use a destination node ID.")
Expand Down Expand Up @@ -1299,7 +1306,15 @@ def initParser():
group.add_argument(
"--request-telemetry",
help="Request telemetry from a node. "
"You need pass the destination ID as argument with '--dest'. "
"You need to pass the destination ID as argument with '--dest'. "
"For repeaters, the nodeNum is required.",
action="store_true",
)

group.add_argument(
"--request-position",
help="Request the position from a nade. "
"You need to pass the destination ID as an argument with '--dest'. "
"For repeaters, the nodeNum is required.",
action="store_true",
)
Expand Down
50 changes: 44 additions & 6 deletions meshtastic/mesh_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,13 +381,50 @@ def sendPosition(
p.time = timeSec
logging.debug(f"p.time:{p.time}")

return self.sendData(
if wantResponse:
onResponse = self.onResponsePosition
else:
onResponse = None

d = self.sendData(
p,
destinationId,
portNum=portnums_pb2.PortNum.POSITION_APP,
wantAck=wantAck,
wantResponse=wantResponse,
onResponse=onResponse,
)
if wantResponse:
self.waitForPosition()
return d

def onResponsePosition(self, p):
"""on response for position"""
if p["decoded"]["portnum"] == 'POSITION_APP':
self._acknowledgment.receivedPosition = True
position = mesh_pb2.Position()
position.ParseFromString(p["decoded"]["payload"])

ret = "Position received: "
if position.latitude_i != 0 and position.longitude_i != 0:
ret += f"({position.latitude_i * 10**-7}, {position.longitude_i * 10**-7})"
else:
ret += "(unknown)"
if position.altitude != 0:
ret += f" {position.altitude}m"

if position.precision_bits not in [0,32]:
ret += f" precision:{position.precision_bits}"
elif position.precision_bits == 32:
ret += " full precision"
elif position.precision_bits == 0:
ret += " position disabled"

print(ret)

elif p["decoded"]["portnum"] == 'ROUTING_APP':
if p["decoded"]["routing"]["errorReason"] == 'NO_RESPONSE':
our_exit("No response from node. At least firmware 2.1.22 is required on the destination node.")

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

if destinationId.startswith("!"):
destinationId = int(destinationId[1:], 16)
else:
destinationId = int(destinationId)

self.sendData(
r,
destinationId=destinationId,
Expand Down Expand Up @@ -573,6 +605,12 @@ def waitForTelemetry(self):
if not success:
raise MeshInterface.MeshInterfaceError("Timed out waiting for telemetry")

def waitForPosition(self):
"""Wait for position"""
success = self._timeout.waitForPosition(self._acknowledgment)
if not success:
raise MeshInterface.MeshInterfaceError("Timed out waiting for position")

def getMyNodeInfo(self) -> Optional[Dict]:
"""Get info about my node."""
if self.myInfo is None or self.nodesByNum is None:
Expand Down
12 changes: 12 additions & 0 deletions meshtastic/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,16 @@ def waitForTelemetry(self, acknowledgment) -> bool:
time.sleep(self.sleepInterval)
return False

def waitForPosition(self, acknowledgment) -> bool:
"""Block until position response is received. Returns True if position response has been received."""
self.reset()
while time.time() < self.expireTime:
if getattr(acknowledgment, "receivedPosition", None):
acknowledgment.reset()
return True
time.sleep(self.sleepInterval)
return False

class Acknowledgment:
"A class that records which type of acknowledgment was just received, if any."

Expand All @@ -216,6 +226,7 @@ def __init__(self):
self.receivedImplAck = False
self.receivedTraceRoute = False
self.receivedTelemetry = False
self.receivedPosition = False

def reset(self):
"""reset"""
Expand All @@ -224,6 +235,7 @@ def reset(self):
self.receivedImplAck = False
self.receivedTraceRoute = False
self.receivedTelemetry = False
self.receivedPosition = False


class DeferredExecution:
Expand Down