Skip to content

Commit 82554a1

Browse files
committed
Add optional parameter to specify what fields to show with --nodes
1 parent 6ec506f commit 82554a1

3 files changed

Lines changed: 64 additions & 4 deletions

File tree

.vscode/launch.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,23 @@
245245
"module": "meshtastic",
246246
"justMyCode": true,
247247
"args": ["--debug", "--nodes"]
248+
},
249+
{
250+
"name": "meshtastic nodes table",
251+
"type": "debugpy",
252+
"request": "launch",
253+
"module": "meshtastic",
254+
"justMyCode": true,
255+
"args": ["--nodes"]
256+
},
257+
{
258+
"name": "meshtastic nodes table with show-fields",
259+
"type": "debugpy",
260+
"request": "launch",
261+
"module": "meshtastic",
262+
"justMyCode": true,
263+
"args": ["--nodes", "--show-fields", "AKA,Pubkey,Role,Role,Role,Latitude,Latitude,deviceMetrics.voltage"]
248264
}
265+
249266
]
250267
}

meshtastic/__main__.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -921,7 +921,11 @@ def setSimpleConfig(modem_preset):
921921
if args.dest != BROADCAST_ADDR:
922922
print("Showing node list of a remote node is not supported.")
923923
return
924-
interface.showNodes()
924+
interface.showNodes(True, args.show_fields)
925+
926+
if args.show_fields and not args.nodes:
927+
print("--show-fields can only be used with --nodes")
928+
return
925929

926930
if args.qr or args.qr_all:
927931
closeNow = True
@@ -1626,6 +1630,13 @@ def addLocalActionArgs(parser: argparse.ArgumentParser) -> argparse.ArgumentPars
16261630
help="Print Node List in a pretty formatted table",
16271631
action="store_true",
16281632
)
1633+
1634+
group.add_argument(
1635+
"--show-fields",
1636+
help="Specify fields to show (comma-separated) when using --nodes",
1637+
type=lambda s: s.split(','),
1638+
default=None
1639+
)
16291640

16301641
return parser
16311642

meshtastic/mesh_interface.py

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ def showInfo(self, file=sys.stdout) -> str: # pylint: disable=W0613
222222
return infos
223223

224224
def showNodes(
225-
self, includeSelf: bool = True
225+
self, includeSelf: bool = True, showFields: Optional[List[str]] = None
226226
) -> str: # pylint: disable=W0613
227227
"""Show table summary of nodes in mesh"""
228228

@@ -246,6 +246,23 @@ def getTimeAgo(ts) -> Optional[str]:
246246
return None # not handling a timestamp from the future
247247
return _timeago(delta_secs)
248248

249+
def getNestedValue(node_dict: Dict[str, Any], key_path: str) -> Any:
250+
keys = key_path.split(".")
251+
value = node_dict
252+
for key in keys:
253+
if isinstance(value, dict):
254+
value = value.get(key)
255+
else:
256+
return None
257+
return value
258+
259+
if showFields is None or showFields.count == 0:
260+
# The default set of fields to show (e.g., the status quo)
261+
showFields = ["N", "User", "ID", "AKA", "Hardware", "Pubkey", "Role", "Latitude", "Longitude", "Altitude", "Battery", "Channel util.", "Tx air util.", "SNR", "Hops", "Channel", "LastHeard", "Since"]
262+
else:
263+
# Always at least include the row number.
264+
showFields.insert(0, "N")
265+
249266
rows: List[Dict[str, Any]] = []
250267
if self.nodesByNum:
251268
logging.debug(f"self.nodes:{self.nodes}")
@@ -287,11 +304,12 @@ def getTimeAgo(ts) -> Optional[str]:
287304
if metrics:
288305
batteryLevel = metrics.get("batteryLevel")
289306
if batteryLevel is not None:
290-
if batteryLevel == 0:
307+
if batteryLevel in (0, 101): # Note: for boards without battery pin or PMU, 101% battery means 'the board is using external power'
291308
batteryString = "Powered"
292309
else:
293310
batteryString = str(batteryLevel) + "%"
294311
row.update({"Battery": batteryString})
312+
295313
row.update(
296314
{
297315
"Channel util.": formatFloat(
@@ -313,7 +331,21 @@ def getTimeAgo(ts) -> Optional[str]:
313331
}
314332
)
315333

316-
rows.append(row)
334+
# This allows the user to specify fields that wouldn't otherwise be included.
335+
extraFields = {}
336+
for field in showFields:
337+
if field in row:
338+
# We already have it, move along.
339+
continue
340+
elif "." in field:
341+
extraFields[field] = getNestedValue(node, field)
342+
else:
343+
extraFields[field] = node.get(field)
344+
345+
# Filter out any field in the data set that was not specified.
346+
filteredData = {key: value for key, value in row.items() if key in showFields}
347+
filteredData.update(extraFields)
348+
rows.append(filteredData)
317349

318350
rows.sort(key=lambda r: r.get("LastHeard") or "0000", reverse=True)
319351
for i, row in enumerate(rows):

0 commit comments

Comments
 (0)