Three kinds of "setting" were tangled into two files and one of them had no screen at all. The radio's settings live on the radio and are edited on Device config. Machine setup -- where the database is, which companion to talk to -- stays in config.toml, a text editor's job. Everything in between was app behaviour: six keys sitting in config.toml with nothing to open them, and a dozen more that were only module constants a reader could never reach. Those are preferences now, and they have a page. core/preferences.py is a PrefSpec registry in the shape of the device-config one -- group, type, bounds, help, and a default -- and the page is built from the same parts as the device editor, deliberately: one grouped lane-aligned list, current -> new staged in warn, Apply/Back appearing only once something is staged, the shared discard confirm on the way out. Two editors that stage values should not be two screens to learn. What it adds is a Defaults section holding one row that stages every changed preference back to its built-in value; it is drawn only while a reset would do something, and it stages rather than writes, so it is as reviewable and as Esc-discardable as any other change and the file is still only ever written by the one action at the bottom. Its rows scroll sideways where the device editor's don't: the explanation is the widest thing on the row and the only part that runs past the edge, so <-> slide it under a pinned setting and value. The file is preferences.yaml and holds only the values you disagree with the code about -- grouped and commented, each entry above its help and its default. That is what lets a later change to a default reach an install that never asked to be exempt; delete a line and the code takes over again. A hand edit gone wrong costs that line, never the session. Every preference is wired to something that reads it. ctx.preferences is the explicit path; preferences.current() is for the render layer, which has no context to reach through, the same reason get_platform() exists. The About pages come along into a This app section, the third scope after this node and other nodes, with Preferences leading it -- the one row there that changes MeshTerm rather than describing it. A section of one would have broken the menu's own no-bucket-of-one rule, and the app's scope is the honest home for both halves anyway. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
60 lines
2.6 KiB
TOML
60 lines
2.6 KiB
TOML
# MeshTerm configuration: where things live, and which device to talk to.
|
|
# Copy to ~/.meshterm/config.toml (or pass --db / --port on the CLI).
|
|
#
|
|
# How MeshTerm itself behaves — transmit cooldown, message retries, how much history it
|
|
# keeps, whether it connects at launch — is *not* here. Those are preferences: they live
|
|
# in ~/.meshterm/preferences.yaml, and are edited on the Preferences page (or with
|
|
# `meshterm preferences set <key> <value>`). Every one has a built-in default, so that
|
|
# file only ever lists what you have changed.
|
|
#
|
|
# Profiles are optional. With no profile, no --port/--ble/--tcp, MeshTerm discovers attached
|
|
# serial devices and nearby Bluetooth companions, lets you pick one (interactively) or uses the
|
|
# single one present, and remembers the last device that connected as the default for next time.
|
|
# A network (TCP) companion isn't discoverable — name it with --tcp host:port, a TCP profile, or
|
|
# the picker's "add a network device" prompt. Define profiles below only to give your hardware
|
|
# stable aliases (e.g. --profile yagi, --profile handheld for Bluetooth, --profile wifi for TCP).
|
|
|
|
default_profile = "s3"
|
|
# Open the radio link as soon as the menu appears. False opens it lazily instead — only
|
|
# once monitoring is turned on or a tool first needs the radio.
|
|
connect_on_start = true
|
|
# db_path = "C:/Users/you/meshterm/meshterm.db"
|
|
|
|
# One [profiles.<name>] block per physical companion device.
|
|
[profiles.s3]
|
|
port = "COM5"
|
|
baudrate = 115200
|
|
default_tx_power = 20
|
|
description = "XIAO ESP32-S3 + Wio SX1262 serial companion"
|
|
|
|
[profiles.yagi]
|
|
port = "COM6"
|
|
description = "Yagi repeater (reaching the wider mesh)"
|
|
|
|
[profiles.local]
|
|
port = "COM7"
|
|
description = "Local-range repeater"
|
|
|
|
[profiles.observer]
|
|
port = "COM8"
|
|
description = "XIAO observer running a bot"
|
|
|
|
# A Bluetooth LE companion: give it an `address` (from `meshterm devices`) instead of a port.
|
|
# The `transport = "ble"` line is optional — a bare `address` already implies Bluetooth.
|
|
[profiles.handheld]
|
|
address = "AA:BB:CC:DD:EE:FF"
|
|
# transport = "ble"
|
|
# ble_pin = "123456" # only if your device requires a pairing PIN
|
|
description = "Pocket handheld over Bluetooth"
|
|
|
|
# A network (TCP) companion — a WiFi board, or a meshcored-style proxy — reachable at a
|
|
# host:port. Give it a `host` (and optional `tcp_port`, default 5000); a bare `host` already
|
|
# implies TCP, so the `transport = "tcp"` line is optional. A TCP companion isn't discoverable,
|
|
# so a profile (or --tcp host:port, or the picker's "add a network device" prompt) is how you
|
|
# reach one.
|
|
[profiles.wifi]
|
|
host = "192.168.1.50"
|
|
# tcp_port = 5000
|
|
# transport = "tcp"
|
|
description = "Basestation over WiFi"
|