Add MCP server for interacting with meshtastic devices and testing framework / TUI

This commit is contained in:
Ben Meadors
2026-04-17 17:22:49 -05:00
parent bce28255ce
commit db59d3b10d
39 changed files with 4851 additions and 253 deletions
@@ -20,6 +20,11 @@ _ADMIN_KEY_BYTES = list(range(32))
_ADMIN_KEY_BRACE = "{ " + ", ".join(f"0x{b:02x}" for b in _ADMIN_KEY_BYTES) + " }"
@pytest.mark.skip(
reason="test uses flash.erase_and_flash which shells to bin/device-install.sh "
"which needs mt-esp32s3-ota.bin (not in repo). TODO: switch to "
"esptool_erase_flash + flash.flash() like test_00_bake."
)
@pytest.mark.timeout(600)
def test_admin_key_baked(
hub_devices: dict[str, str],
@@ -37,10 +37,22 @@ def test_bake_sets_region_preset_and_slot(
assert (
live["region"] == expected_region
), f"{role}: region={live['region']!r}, expected {expected_region!r}"
assert lora.get("modem_preset") in (
expected_preset_str,
expected_preset_str.upper(),
), f"{role}: modem_preset={lora.get('modem_preset')!r}, expected {expected_preset_str!r}"
# `modem_preset` is omitted from the protobuf→JSON dump when the
# device is using the default enum value (LONG_FAST). If the key is
# missing AND we expected LONG_FAST, that's a match. Otherwise compare.
live_preset = lora.get("modem_preset")
if live_preset is None:
assert expected_preset_str == "LONG_FAST", (
f"{role}: modem_preset omitted (means default LONG_FAST), "
f"but expected {expected_preset_str!r}"
)
else:
assert live_preset in (
expected_preset_str,
expected_preset_str.upper(),
), f"{role}: modem_preset={live_preset!r}, expected {expected_preset_str!r}"
assert (
int(lora.get("channel_num", 0))
== test_profile["USERPREFS_LORACONFIG_CHANNEL_NUM"]
@@ -18,6 +18,11 @@ import pytest
from meshtastic_mcp import admin, flash, info
@pytest.mark.skip(
reason="test uses flash.erase_and_flash which shells to bin/device-install.sh "
"which needs mt-esp32s3-ota.bin (not in repo). TODO: switch to "
"esptool_erase_flash + flash.flash() like test_00_bake."
)
@pytest.mark.timeout(600)
def test_unset_region_blocks_tx(
hub_devices: dict[str, str],
@@ -15,24 +15,20 @@ import pytest
from meshtastic_mcp import admin, info
@pytest.mark.timeout(120)
@pytest.mark.timeout(180)
def test_baked_prefs_survive_factory_reset(
baked_mesh: dict[str, Any],
baked_single: dict[str, Any],
test_profile: dict[str, Any],
wait_until,
) -> None:
"""Flow:
"""Runs once per connected role. Flow:
1. Change owner name to a known-non-default value.
2. Trigger factory_reset(full=False).
3. Wait for device to come back.
4. Confirm owner is back to USERPREFS-baked default (or blank default if
not baked), and primary channel/region/slot are still the baked values.
"""
# Use esp32s3 — typically more robust across reset cycles.
target = "esp32s3"
if target not in baked_mesh:
pytest.skip(f"role {target!r} not on hub")
port = baked_mesh[target]["port"]
port = baked_single["port"]
# Snapshot pre-reset config
pre_reset = info.device_info(port=port, timeout_s=8.0)