d652a4e012d80a1998500e673536ba3fc92bc58d
New `map` tool (menu + `meshtools map` CLI) that plots the mesh's location-sharing nodes over a real OSM street basemap rendered as Unicode braille — streets, rivers, water, and place names — the mapscii idea, but able to plot our own nodes and live inside the TUI. - core/mvt.py: dependency-free MVT/protobuf vector-tile decoder. - core/geo.py: Web Mercator + a pannable/zoomable Viewport and tile math. - services/basemap.py: OpenFreeMap vector tiles (free, no API key), resolved from the versioned TileJSON, disk-cached, offline-safe (stdlib urllib only). - ui/mapcanvas.py: colored braille canvas (per-cell priority, line raster, polygon fill, collision-avoided labels), emits truecolor ANSI. - ui/map_render.py: compositor — basemap styling + node markers with names. - ui/map_screen.py: full-screen screen; wasd/arrows pan, =/- zoom, r reset, Esc/q exit; background tile loading. Offline falls back to nodes on a grid. - tools/map.py: interactive in the menu, one-shot static render on the CLI. Repeaters are prioritised over leaf nodes via advert type: threaded `node_type` through Observation/HeardNode and the persistence layer (schema v4->v5, with an idempotent migration adding observations.node_type). Added TuiSession.base_body_size() so a full-screen screen can size itself to the frame. Tests: tests/test_map.py (24) cover MVT decode against a real cached tile fixture, projection, the canvas, the compositor, offline behavior, and the interactive pan/zoom/reset logic. Full suite: 261 passing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
MeshTools
A modern, extensible command-line toolkit for tuning and exploring a MeshCore mesh through a serial-connected companion device.
MeshTools is interactive by default (a Rich + Questionary menu) and fully scriptable (every menu option is also a Typer subcommand). Every run is logged to SQLite and can be turned into interactive HTML visualizations.
Features
| Feature | Status | What it does |
|---|---|---|
| Trace | ✅ skeleton | Run repeated path traces to a target and aggregate per-hop SNR. |
| Device info | ✅ skeleton | Show the connected companion device's identity and radio config. |
| Node list | ✅ working | List this node and its known contacts — full public keys with the path-hash prefix highlighted. |
| Device config | ✅ working | View and change every setting (name, radio, behavior, experimental), with TOML backup/restore, channels, and gated destructive ops. |
| Device discovery | ✅ working | Enumerate serial devices, pick one interactively, and remember the last good default. |
| History / DB | ✅ skeleton | Every tool execution and measurement is persisted and queryable. |
| TX-power optimization | ✅ working | Sweep transmit power (coarse + refine), converge on the best signal, optionally apply, render an interactive chart. |
| Link budget | ✅ working | Predict time-on-air, receiver sensitivity, range, and duty-cycle/dwell headroom for a radio config — offline, no radio needed. |
| Chat | ✅ working | Live full-screen channel and direct messaging — a scrolling transcript with a pinned input line where sent and received messages stream together. Every message is logged to SQLite, unread counts show in the menu header, and chat send/history/list script the same from the CLI. Channels are picked here; edit them in config. |
| Passive monitor | ✅ working | Toggle a non-blocking background logger that records every overheard advert/telemetry (SNR, RSSI, location) to a longitudinal history while you keep using the app; on/off is remembered between sessions and live packet counts show in the menu. |
| Link health | ✅ working | Compare a target's recent traces to its rolling baseline and flag SNR/reliability regressions, end-to-end and per hop. |
| Route map | ✅ working | Aggregate trace history into an interactive route-stability graph — which links are stable, which the mesh flaps between, with churn metrics. |
| Path optimization | 🚧 planned | Discover and score mesh paths from neighbors outward. |
| Visualizations | 🟡 partial | Plotly TX-sweep chart (HTML) done; pyvis mesh graph + time-series planned. |
Install
pip install -e ".[dev]"
Python 3.10+ is required (matching the meshcore library).
Usage
# Interactive menu (default)
meshtools
# Scripted: every menu option is also a subcommand
meshtools trace --target Alice --samples 10 --profile yagi
# Force a route through specific repeaters (MeshCore-app style): comma-separated
# contact names and/or hex key prefixes, mixed freely. Blank lets the device route.
meshtools trace --target Alice --path "3d,f2,3d"
meshtools trace --target Alice --path "3d,Bravo-Repeater,f2"
meshtools tx-optimize --target Alice --samples 6 --step 3 --apply
meshtools info
meshtools history
# Messaging: live chat in the menu, or scripted from the CLI
meshtools chat # interactive: pick a conversation, chat live
meshtools chat send --to Alice "on my way" # direct message
meshtools chat send --channel 0 "net in 5" # channel broadcast
meshtools chat history --to Alice
meshtools chat list
# Device configuration: view, set, back up, restore
meshtools config # show all current settings
meshtools config set radio_sf 9 # change one setting
meshtools config backup node.toml # archive every setting to TOML
meshtools config restore node.toml --dry-run
# No radio attached? Use the built-in simulator for development.
meshtools --mock trace --target Alice
Architecture
MeshTools is layered so features are added by dropping a single file in meshtools/tools/:
cli.py Typer app; no subcommand -> interactive menu
context.py AppContext (console, config, repository, device) dependency container
core/ Domain: models, config + device profiles, connection abstraction (+ mock)
tools/ Pluggable "menu options"; each self-registers and gets logging for free
services/ Algorithms (trace aggregation, tx search, path exploration) — no UI
persistence/ SQLite schema, repository, structured logging
ui/ Rich theme/widgets + Questionary menu
viz/ Plotly / pyvis renderers -> HTML & PNG
Adding a feature means subclassing Tool, decorating it with @register, and
implementing run(). The same registry builds both the CLI and the menu, and the base
class wraps every execution in a logged runs row automatically.
Languages
Python
99.1%
Shell
0.9%