MeshTools is a Rich+Questionary interactive / Typer-scriptable toolkit for tuning a MeshCore mesh over a serial companion device, with SQLite-logged runs and Plotly visualizations. Includes the skeleton (trace, info, history), TX-power optimization, and a MockDevice simulator (--mock). Device discovery & selection: - core/discovery.py: enumerate serial ports (pyserial), flag/sort likely LoRa hardware by USB vendor id, stable_id for replug-safe identity. - core/device_store.py: remember the last successfully connected device in <config_dir>/devices.json (independent of --db). - core/selection.py: non-interactive resolver (--port > profile > remembered > sole device > guidance error) for the CLI. - ui/device_picker.py + menu startup: interactive picker preselecting the remembered default; banner reflects the choice. - tools/devices.py: `meshtools devices` lists/marks attached devices. - AppContext resolves the port and records last-known-good on connect success. Fixes: - theme.py: force UTF-8 on stdout/stderr so glyphs don't crash legacy consoles. - connection.py: friendly message when meshcore is missing; pin meshcore>=2.3. - trace/tx-optimize: fall back to free-text target entry when the device reports no contacts (autocomplete requires non-empty choices). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
31 lines
910 B
Python
31 lines
910 B
Python
"""Pluggable tools (menu options / CLI subcommands).
|
|
|
|
Importing this package eagerly imports every tool module so that each one's ``@register``
|
|
decorator populates the shared registry. New features only need to add a module here.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib
|
|
import pkgutil
|
|
|
|
from .base import Tool, all_tools, get_tool, register
|
|
|
|
__all__ = ["Tool", "all_tools", "get_tool", "register", "load_all_tools"]
|
|
|
|
|
|
def load_all_tools() -> None:
|
|
"""Import every sibling module so its tools self-register.
|
|
|
|
Modules whose names start with an underscore (and ``base``) are skipped.
|
|
"""
|
|
package = __name__
|
|
for mod in pkgutil.iter_modules(__path__):
|
|
if mod.name.startswith("_") or mod.name == "base":
|
|
continue
|
|
importlib.import_module(f"{package}.{mod.name}")
|
|
|
|
|
|
# Populate the registry on import so the CLI and menu see every tool.
|
|
load_all_tools()
|