mirror of
https://github.com/meshtastic/python.git
synced 2026-01-10 00:37:55 -05:00
Merge pull request #457 from GUVWAF/reqTelemetry
Add `request-telemetry` option
This commit is contained in:
@@ -412,6 +412,13 @@ def onConnected(interface):
|
||||
print(f"Sending traceroute request to {dest} (this could take a while)")
|
||||
interface.sendTraceRoute(dest, hopLimit)
|
||||
|
||||
if args.request_telemetry:
|
||||
if args.dest == BROADCAST_ADDR:
|
||||
meshtastic.util.our_exit("Warning: Must use a destination node ID.")
|
||||
else:
|
||||
print(f"Sending telemetry request to {args.dest} (this could take a while)")
|
||||
interface.sendTelemetry(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.")
|
||||
@@ -1188,6 +1195,14 @@ def initParser():
|
||||
"Only nodes that have the encryption key can be traced.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--request-telemetry",
|
||||
help="Request telemetry from a node. "
|
||||
"You need pass the destination ID as argument with '--dest'. "
|
||||
"For repeaters, the nodeNum is required.",
|
||||
action="store_true",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--ack",
|
||||
help="Use in combination with --sendtext to wait for an acknowledgment.",
|
||||
|
||||
@@ -18,7 +18,7 @@ from pubsub import pub
|
||||
from tabulate import tabulate
|
||||
|
||||
import meshtastic.node
|
||||
from meshtastic import mesh_pb2, portnums_pb2
|
||||
from meshtastic import mesh_pb2, portnums_pb2, telemetry_pb2
|
||||
from meshtastic.__init__ import (
|
||||
BROADCAST_ADDR,
|
||||
BROADCAST_NUM,
|
||||
@@ -409,6 +409,70 @@ class MeshInterface:
|
||||
|
||||
self._acknowledgment.receivedTraceRoute = True
|
||||
|
||||
def sendTelemetry(self, destinationId=BROADCAST_ADDR, wantResponse=False):
|
||||
"""Send telemetry and optionally ask for a response"""
|
||||
r = telemetry_pb2.Telemetry()
|
||||
|
||||
node = next(n for n in self.nodes.values() if n["num"] == self.localNode.nodeNum)
|
||||
if node is not None:
|
||||
metrics = node.get("deviceMetrics")
|
||||
if metrics:
|
||||
batteryLevel = metrics.get("batteryLevel")
|
||||
if batteryLevel is not None:
|
||||
r.device_metrics.battery_level = batteryLevel
|
||||
voltage = metrics.get("voltage")
|
||||
if voltage is not None:
|
||||
r.device_metrics.voltage = voltage
|
||||
channel_utilization = metrics.get("channelUtilization")
|
||||
if channel_utilization is not None:
|
||||
r.device_metrics.channel_utilization = channel_utilization
|
||||
air_util_tx = metrics.get("airUtilTx")
|
||||
if air_util_tx is not None:
|
||||
r.device_metrics.air_util_tx = air_util_tx
|
||||
|
||||
if wantResponse:
|
||||
onResponse = self.onResponseTelemetry
|
||||
else:
|
||||
onResponse = None
|
||||
|
||||
if destinationId.startswith("!"):
|
||||
destinationId = int(destinationId[1:], 16)
|
||||
else:
|
||||
destinationId = int(destinationId)
|
||||
|
||||
self.sendData(
|
||||
r,
|
||||
destinationId=destinationId,
|
||||
portNum=portnums_pb2.PortNum.TELEMETRY_APP,
|
||||
wantResponse=wantResponse,
|
||||
onResponse=onResponse,
|
||||
)
|
||||
if wantResponse:
|
||||
self.waitForTelemetry()
|
||||
|
||||
def onResponseTelemetry(self, p):
|
||||
"""on response for telemetry"""
|
||||
if p["decoded"]["portnum"] == 'TELEMETRY_APP':
|
||||
self._acknowledgment.receivedTelemetry = True
|
||||
telemetry = telemetry_pb2.Telemetry()
|
||||
telemetry.ParseFromString(p["decoded"]["payload"])
|
||||
|
||||
print("Telemetry received:")
|
||||
if telemetry.device_metrics.battery_level is not None:
|
||||
print(f"Battery level: {telemetry.device_metrics.battery_level:.2f}%")
|
||||
if telemetry.device_metrics.voltage is not None:
|
||||
print(f"Voltage: {telemetry.device_metrics.voltage:.2f} V")
|
||||
if telemetry.device_metrics.channel_utilization is not None:
|
||||
print(
|
||||
f"Total channel utilization: {telemetry.device_metrics.channel_utilization:.2f}%"
|
||||
)
|
||||
if telemetry.device_metrics.air_util_tx is not None:
|
||||
print(f"Transmit air utilization: {telemetry.device_metrics.air_util_tx:.2f}%")
|
||||
|
||||
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 _addResponseHandler(self, requestId, callback):
|
||||
self.responseHandlers[requestId] = ResponseHandler(callback)
|
||||
|
||||
@@ -491,6 +555,12 @@ class MeshInterface:
|
||||
success = self._timeout.waitForTraceRoute(waitFactor, self._acknowledgment)
|
||||
if not success:
|
||||
raise Exception("Timed out waiting for traceroute")
|
||||
|
||||
def waitForTelemetry(self):
|
||||
"""Wait for telemetry"""
|
||||
success = self._timeout.waitForTelemetry(self._acknowledgment)
|
||||
if not success:
|
||||
raise Exception("Timed out waiting for telemetry")
|
||||
|
||||
def getMyNodeInfo(self):
|
||||
"""Get info about my node."""
|
||||
|
||||
@@ -192,7 +192,16 @@ class Timeout:
|
||||
return True
|
||||
time.sleep(self.sleepInterval)
|
||||
return False
|
||||
|
||||
|
||||
def waitForTelemetry(self, acknowledgment):
|
||||
"""Block until telemetry response is received. Returns True if telemetry response has been received."""
|
||||
self.reset()
|
||||
while time.time() < self.expireTime:
|
||||
if getattr(acknowledgment, "receivedTelemetry", 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."
|
||||
@@ -203,6 +212,7 @@ class Acknowledgment:
|
||||
self.receivedNak = False
|
||||
self.receivedImplAck = False
|
||||
self.receivedTraceRoute = False
|
||||
self.receivedTelemetry = False
|
||||
|
||||
def reset(self):
|
||||
"""reset"""
|
||||
@@ -210,6 +220,7 @@ class Acknowledgment:
|
||||
self.receivedNak = False
|
||||
self.receivedImplAck = False
|
||||
self.receivedTraceRoute = False
|
||||
self.receivedTelemetry = False
|
||||
|
||||
|
||||
class DeferredExecution:
|
||||
|
||||
Reference in New Issue
Block a user