Skip to content
Draft
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
23 changes: 23 additions & 0 deletions meshtastic/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,21 @@ def onConnected(interface):
telemetryType=telemType,
)

if args.request_nodeinfo:
if args.dest == BROADCAST_ADDR:
meshtastic.util.our_exit("Warning: Must use a destination node ID.")
else:
channelIndex = mt_config.channel_index or 0
if checkChannel(interface, channelIndex):
print(
f"Sending NodeInfo request to {args.dest} on channelIndex:{channelIndex} (this could take a while)"
)
interface.requestNodeInfo(
destinationId=args.dest,
wantResponse=True,
channelIndex=channelIndex,
)

if args.request_position:
if args.dest == BROADCAST_ADDR:
meshtastic.util.our_exit("Warning: Must use a destination node ID.")
Expand Down Expand Up @@ -2267,6 +2282,14 @@ def addRemoteActionArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentPar
metavar="TYPE",
)

group.add_argument(
"--request-nodeinfo",
help="Request NodeInfo (name, hardware model, etc) from a node. "
"You need to pass the destination ID as an argument with '--dest'. "
"For repeaters, the nodeNum is required.",
action="store_true",
)

group.add_argument(
"--request-position",
help="Request the position from a node. "
Expand Down
45 changes: 45 additions & 0 deletions meshtastic/mesh_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,35 @@ def sendData(
p = self._sendPacket(meshPacket, destinationId, wantAck=wantAck, hopLimit=hopLimit, pkiEncrypted=pkiEncrypted, publicKey=publicKey)
return p

def requestNodeInfo(
self,
destinationId: Union[int, str] = BROADCAST_ADDR,
wantResponse: bool = False,
channelIndex: int = 0,
hopLimit: Optional[int] = None,
):
"""Send a NodeInfo request and optionally ask for a response"""
u = mesh_pb2.User()

if wantResponse:
onResponse = self.onResponseNodeInfo
else:
onResponse = None

d = self.sendData(
u,
destinationId=destinationId,
portNum=portnums_pb2.PortNum.NODEINFO_APP,
wantResponse=wantResponse,
onResponse=onResponse,
channelIndex=channelIndex,
hopLimit=hopLimit,
)

if wantResponse:
self.waitForNodeInfo()
return d

def sendPosition(
self,
latitude: float = 0.0,
Expand Down Expand Up @@ -634,6 +663,16 @@ def sendPosition(
self.waitForPosition()
return d

def onResponseNodeInfo(self, p: dict):
"""on response for NodeInfo"""
if p["decoded"]["portnum"] == "NODEINFO_APP":
self._acknowledgment.receivedNodeInfo = True
if "user" in p["decoded"]:
print("NodeInfo received:")
for key, value in p["decoded"]["user"].items():
if key != "raw":
print(f"{key}: {value}")

def onResponsePosition(self, p):
"""on response for position"""
if p["decoded"]["portnum"] == "POSITION_APP":
Expand Down Expand Up @@ -1067,6 +1106,12 @@ def waitForTelemetry(self):
if not success:
raise MeshInterface.MeshInterfaceError("Timed out waiting for telemetry")

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

def waitForPosition(self):
"""Wait for position"""
success = self._timeout.waitForPosition(self._acknowledgment)
Expand Down
12 changes: 12 additions & 0 deletions meshtastic/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,16 @@ def waitForWaypoint(self, acknowledgment) -> bool:
time.sleep(self.sleepInterval)
return False

def waitForNodeInfo(self, acknowledgment) -> bool:
"""Block until NodeInfo response is received. Returns True if NodeInfo response has been received."""
self.reset()
while time.time() < self.expireTime:
if getattr(acknowledgment, "receivedNodeInfo", 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 @@ -278,6 +288,7 @@ def __init__(self) -> None:
self.receivedTelemetry = False
self.receivedPosition = False
self.receivedWaypoint = False
self.receivedNodeInfo = False

def reset(self) -> None:
"""reset"""
Expand All @@ -288,6 +299,7 @@ def reset(self) -> None:
self.receivedTelemetry = False
self.receivedPosition = False
self.receivedWaypoint = False
self.receivedNodeInfo = False


class DeferredExecution:
Expand Down