Merge pull request #82 from timgunter/show_nodes

Enhancements to showInfo() and printNodes()/showNodes()
This commit is contained in:
Kevin Hester
2021-04-12 14:27:37 +08:00
committed by GitHub
2 changed files with 61 additions and 60 deletions

View File

@@ -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"""

View File

@@ -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