mirror of
https://github.com/meshtastic/python.git
synced 2026-01-01 20:38:03 -05:00
Merge pull request #82 from timgunter/show_nodes
Enhancements to showInfo() and printNodes()/showNodes()
This commit is contained in:
@@ -67,11 +67,14 @@ import time
|
||||
import base64
|
||||
import platform
|
||||
import socket
|
||||
import timeago
|
||||
from . import mesh_pb2, portnums_pb2, apponly_pb2, admin_pb2, environmental_measurement_pb2, remote_hardware_pb2, channel_pb2, radioconfig_pb2, util
|
||||
from .util import fixme, catchAndIgnore, stripnl, DeferredExecution, Timeout
|
||||
from .node import Node
|
||||
from pubsub import pub
|
||||
from dotmap import DotMap
|
||||
from datetime import datetime
|
||||
from tabulate import tabulate
|
||||
from typing import *
|
||||
from google.protobuf.json_format import MessageToJson
|
||||
|
||||
@@ -160,12 +163,65 @@ class MeshInterface:
|
||||
logging.error(f'Traceback: {traceback}')
|
||||
self.close()
|
||||
|
||||
def showInfo(self):
|
||||
def showInfo(self, file=sys.stdout):
|
||||
"""Show human readable summary about this object"""
|
||||
print(f"My info: {stripnl(MessageToJson(self.myInfo))}")
|
||||
print("\nNodes in mesh:")
|
||||
|
||||
print(f"Owner: {self.getLongName()} ({self.getShortName()})", file=file)
|
||||
print(f"\nMy info: {stripnl(MessageToJson(self.myInfo))}", file=file)
|
||||
print("\nNodes in mesh:", file=file)
|
||||
for n in self.nodes.values():
|
||||
print(" " + stripnl(n))
|
||||
print(f" {stripnl(n)}", file=file)
|
||||
|
||||
def showNodes(self, includeSelf=True, file=sys.stdout):
|
||||
"""Show table summary of nodes in mesh"""
|
||||
def formatFloat(value, precision=2, unit=''):
|
||||
return f'{value:.{precision}f}{unit}' if value else None
|
||||
|
||||
def getLH(ts):
|
||||
return datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') if ts else None
|
||||
|
||||
def getTimeAgo(ts):
|
||||
return timeago.format(datetime.fromtimestamp(ts), datetime.now()) if ts else None
|
||||
|
||||
rows = []
|
||||
for node in self.nodes.values():
|
||||
if not includeSelf and node['num'] == self.localNode.nodeNum:
|
||||
continue
|
||||
|
||||
row = { "N": 0 }
|
||||
|
||||
user = node.get('user')
|
||||
if user:
|
||||
row.update({
|
||||
"User": user['longName'],
|
||||
"AKA": user['shortName'],
|
||||
"ID": user['id'],
|
||||
})
|
||||
|
||||
pos = node.get('position')
|
||||
if pos:
|
||||
row.update({
|
||||
"Latitude": formatFloat(pos.get("latitude"), 4, "°"),
|
||||
"Longitude": formatFloat(pos.get("longitude"), 4, "°"),
|
||||
"Altitude": formatFloat(pos.get("altitude"), 0, " m"),
|
||||
"Battery": formatFloat(pos.get("batteryLevel"), 2, "%"),
|
||||
})
|
||||
|
||||
row.update({
|
||||
"SNR": formatFloat(node.get("snr"), 2, " dB"),
|
||||
"LastHeard": getLH( node.get("lastHeard")),
|
||||
"Since": getTimeAgo( node.get("lastHeard")),
|
||||
})
|
||||
|
||||
rows.append(row)
|
||||
|
||||
# Why doesn't this way work?
|
||||
#rows.sort(key=lambda r: r.get('LastHeard', '0000'), reverse=True)
|
||||
rows.sort(key=lambda r: r.get('LastHeard') or '0000', reverse=True)
|
||||
for i, row in enumerate(rows):
|
||||
row['N'] = i+1
|
||||
|
||||
print(tabulate(rows, headers='keys', missingval='N/A', tablefmt='fancy_grid'), file=file)
|
||||
|
||||
def getNode(self, nodeId):
|
||||
"""Return a node object which contains device settings and channel info"""
|
||||
|
||||
@@ -15,9 +15,6 @@ import google.protobuf.json_format
|
||||
import pyqrcode
|
||||
import traceback
|
||||
import pkg_resources
|
||||
from datetime import datetime
|
||||
import timeago
|
||||
from tabulate import tabulate
|
||||
|
||||
"""We only import the tunnel code if we are on a platform that can run it"""
|
||||
have_tunnel = platform.system() == 'Linux'
|
||||
@@ -119,57 +116,6 @@ def fromStr(valstr):
|
||||
never = 0xffffffff
|
||||
oneday = 24 * 60 * 60
|
||||
|
||||
# Returns formatted value
|
||||
|
||||
|
||||
def formatFloat(value, formatStr="{:.2f}", unit="", default="N/A"):
|
||||
return formatStr.format(value)+unit if value else default
|
||||
|
||||
# Returns Last Heard Time in human readable format
|
||||
|
||||
|
||||
def getLH(ts, default="N/A"):
|
||||
return datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') if ts else default
|
||||
|
||||
# Returns time ago for the last heard
|
||||
|
||||
|
||||
def getTimeAgo(ts, default="N/A"):
|
||||
return timeago.format(datetime.fromtimestamp(ts), datetime.now()) if ts else default
|
||||
|
||||
# Print Nodes
|
||||
|
||||
|
||||
def printNodes(nodes, myId):
|
||||
# Create the table and define the structure
|
||||
tableData = []
|
||||
for node in nodes:
|
||||
if node['user']['id'] == myId:
|
||||
continue
|
||||
# aux var to get not defined keys
|
||||
lat = lon = alt = batt = "N/A"
|
||||
if node.get('position'):
|
||||
lat = formatFloat(node['position'].get("latitude"), "{:.4f}", "°")
|
||||
lon = formatFloat(node['position'].get("longitude"), "{:.4f}", "°")
|
||||
alt = formatFloat(node['position'].get("altitude"), "{:.0f}", " m")
|
||||
batt = formatFloat(node['position'].get(
|
||||
"batteryLevel"), "{:.2f}", "%")
|
||||
snr = formatFloat(node.get("snr"), "{:.2f}", " dB")
|
||||
LH = getLH(node.get("lastHeard"))
|
||||
timeAgo = getTimeAgo(node.get("lastHeard"))
|
||||
tableData.append({"N": 0, "User": node['user']['longName'],
|
||||
"AKA": node['user']['shortName'], "ID": node['user']['id'],
|
||||
"Position": lat+", "+lon+", "+alt,
|
||||
"Battery": batt, "SNR": snr,
|
||||
"LastHeard": LH, "Since": timeAgo})
|
||||
|
||||
Rows = sorted(tableData, key=lambda k: k['LastHeard'], reverse=True)
|
||||
RowsOk = sorted(Rows, key=lambda k: k['LastHeard'].startswith("N/A"))
|
||||
for i in range(len(RowsOk)):
|
||||
RowsOk[i]['N'] = i+1
|
||||
|
||||
print(tabulate(RowsOk, headers='keys', tablefmt='fancy_grid'))
|
||||
|
||||
|
||||
def setPref(attributes, name, valStr):
|
||||
"""Set a channel or preferences value"""
|
||||
@@ -427,8 +373,7 @@ def onConnected(interface):
|
||||
|
||||
if args.nodes:
|
||||
closeNow = True
|
||||
printNodes(interface.nodes.values(),
|
||||
interface.getMyNodeInfo()['user']['id'])
|
||||
interface.showNodes()
|
||||
|
||||
if args.qr:
|
||||
closeNow = True
|
||||
|
||||
Reference in New Issue
Block a user