The manuals describe what the code and scripts do today
Every manual was read against the code, the scripts and the upstream sources, and the samples in docs/cli.md were recaptured under --mock where they had drifted. The one a newcomer would hit first: config.example.toml set default_profile to a COM5 profile. Copied verbatim, as configuration.md says to, it broke every device command on a machine with no COM5. default_profile is commented out now, so the copied file leaves discovery working. default_tx_power goes from both, because nothing reads it. docs/cli.md: config show has 22 settings and preferences show 21, not 20 and 8; monitor's blocks have no blank line between them; the diagnostics sample is labelled as a real-radio example with absolute instants and every table; an unknown key exits 1; devices, role and records describe the values they really produce; no maintainer paths; and the "used to" passages describe the present, since a first-time reader never saw the past. picocalc.md: the Calculinux image carries a build stamp, so the gunzip and dd lines take a wildcard; the front SD slot stays empty on first boot; masking wifi-kick is what stops it, and time-sync is disabled with it; updates run the scripts from the pulled checkout with TMPDIR set; the tested list names only what a test checks; git ships in the base image; a bare meshterm shows the splash, and -p picocalc skips it. uconsole.md: an AIO v2 needs MESHCORE_EN_PINS=27 whichever runtime is installed; the bookworm paragraph states what upstream actually ships; the bridge shares the key but keeps its own contacts and radio settings; the defaults are the US/Canada preset; Step 7 downloads what it installs; updating ends with a restart; no claim of test coverage the suite does not have. terminals.md, features.md, hardware.md, cookbook.md, configuration.md and the scripts READMEs get the smaller corrections their audits found. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
9b2b4d784b
commit
5fbba275f6
12 files changed
+279
-179
No files matched your search
+7
-6
@@ -2,10 +2,9 @@
|
||||
# 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.toml, 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.
|
||||
# keeps — is *not* here. Those are preferences: they live in ~/.meshterm/preferences.toml,
|
||||
# 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
|
||||
@@ -14,7 +13,10 @@
|
||||
# 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"
|
||||
# Uncomment and name one of your own profiles below to make it the default. Left
|
||||
# commented, MeshTerm finds the device itself, as described above.
|
||||
# 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
|
||||
@@ -24,7 +26,6 @@ connect_on_start = true
|
||||
[profiles.s3]
|
||||
port = "COM5"
|
||||
baudrate = 115200
|
||||
default_tx_power = 20
|
||||
description = "XIAO ESP32-S3 + Wio SX1262 serial companion"
|
||||
|
||||
[profiles.yagi]
|
||||
|
||||
+2
-1
@@ -38,7 +38,8 @@ USB, Bluetooth or Wi-Fi needs none of this.
|
||||
Two surveys of the code, written the same day against the same commit. They are kept
|
||||
because a project that writes down its own problems is easier to trust than one that
|
||||
doesn't — but they are **snapshots of a date, not to-do lists**. Some of what they
|
||||
describe has been fixed since, and each says so where it has.
|
||||
describe has been fixed since. The navigation survey marks what was resolved; the UI
|
||||
survey does not.
|
||||
|
||||
| Read | For |
|
||||
| --- | --- |
|
||||
|
||||
+83
-56
@@ -13,13 +13,11 @@ It prints two ways, and the difference is who is reading.
|
||||
`2026-09-08T04:26:00-04:00`, and a route is drawn with arrows.
|
||||
- The **JSON face** (`--json`) is for a program, often on another machine and often later.
|
||||
It is the contract: typed values, absent spelled `null`, timestamps in UTC, keys that do
|
||||
not move. It works on **every** command — it used to reach two out of twenty.
|
||||
not move. It works on **every** command.
|
||||
|
||||
The CLI used to make one promise to both of them — that it was written to be read by
|
||||
`awk` — and every rule followed from that. That promise now belongs to `--json`, which
|
||||
keeps it properly, and the plain face is released from it. If you are splitting output on
|
||||
whitespace to feed a script, stop: `--json` exists so you do not have to, and the plain
|
||||
face is no longer holding still for you.
|
||||
The promise to be read by a program belongs to `--json`. The plain face makes no such
|
||||
promise. If you are splitting output on whitespace to feed a script, stop: `--json` exists
|
||||
so you do not have to, and the plain face may change between releases.
|
||||
|
||||
- [Running it](#running-it)
|
||||
- [Where MeshTerm keeps its state](#where-meshterm-keeps-its-state)
|
||||
@@ -123,7 +121,8 @@ it keeps the simulator's invented mesh out of your history, not out of the cache
|
||||
## About the examples
|
||||
|
||||
**Every sample below was captured from a real run against the built-in simulator**
|
||||
(`--mock`), in a throwaway `MESHTERM_HOME`. None of it is typed out by hand. The simulator
|
||||
(`--mock`), in a throwaway `MESHTERM_HOME`, except the `diagnostics` sample, which says so
|
||||
where it appears. None of it is typed out by hand. The simulator
|
||||
answers as a companion would — it has four contacts (`Alice`, `Yagi-Repeater`,
|
||||
`Local-Repeater`, `Observer-Bot`), it adverts, it replies to traces — so the shapes are
|
||||
real even where the numbers are invented.
|
||||
@@ -176,11 +175,10 @@ Yagi-Repeater repeater 7m - a1 45.50190,-73.56740 a1b2c3d40000000
|
||||
Alice node 7m - d4 - d4e5f6a700000000000000000000000000000000000000000000000000000000
|
||||
```
|
||||
|
||||
Names used to be quoted, so that `awk` could split on the quote and get one field out of a
|
||||
name holding a space. That bought one reader a delimiter and cost every other reader a
|
||||
line full of punctuation. The **escaping under the quoting stays and always will**: a node
|
||||
broadcasts its own name and a stranger fills in a message body, so neither may hold a raw
|
||||
control character or end the record it sits in.
|
||||
Names are not quoted. Quoting would give a script a delimiter and give every person a
|
||||
line full of punctuation. Names **are escaped**: a node broadcasts its own name and a
|
||||
stranger fills in a message body, so neither may hold a raw control character or end the
|
||||
record it sits in.
|
||||
|
||||
**A time is an age**, because "recently?" is the question a listing is opened to answer:
|
||||
`now`, `5m`, `3h`, `never`. An absolute instant survives where the instant *is* the fact —
|
||||
@@ -260,12 +258,12 @@ last so it can push nothing.
|
||||
**No wrapping, with one exception.** A record is a line; wrapping would put half a
|
||||
record's fields under the wrong headings, so nothing folds and a long line runs off the
|
||||
right. The exception is the four written pages (`about`, `about-author`, `discord`,
|
||||
`support`), which now wrap at 72 cells. The no-wrap rule exists to protect a record's
|
||||
`support`), which wrap at 72 cells. The no-wrap rule exists to protect a record's
|
||||
fields; a paragraph has no fields, and unwrapped it is a 600-cell line no terminal can
|
||||
read.
|
||||
|
||||
**stdout is the answer; everything else is stderr** — errors (`meshterm: what went
|
||||
wrong`), progress bars, log records, and now the two things that used to be thrown away:
|
||||
wrong`), progress bars, log records, acknowledgements and closing messages:
|
||||
|
||||
```console
|
||||
$ meshterm config set radio_sf 9
|
||||
@@ -275,10 +273,9 @@ $ meshterm config set radio_sf 9 2>&1
|
||||
```
|
||||
|
||||
An **acknowledgement** ("✓ device clock set") and a command's closing **message** ("0
|
||||
records stored") are reassurance a person needs and a script does not. They used to be
|
||||
dropped on the CLI entirely. Sending them to stderr keeps the promise the dropping was
|
||||
made to keep — `meshterm contacts > contacts.txt` still puts contacts in the file and
|
||||
nothing else — while giving the person at the prompt back their tick and their count.
|
||||
records stored") are reassurance a person needs and a script does not. Sending them to
|
||||
stderr means `meshterm contacts > contacts.txt` puts contacts in the file and nothing
|
||||
else, while the person at the prompt still sees their tick and their count.
|
||||
|
||||
---
|
||||
|
||||
@@ -428,7 +425,7 @@ The return value is half the report, on both faces.
|
||||
| Code | Meaning |
|
||||
| --- | --- |
|
||||
| `0` | Success. |
|
||||
| `1` | Failure with no more specific code — an unreadable file, an unhandled fault. |
|
||||
| `1` | Failure with no more specific code — an unreadable file, an unknown setting or preference key (`config set`, `preferences set`), an unhandled fault. |
|
||||
| `2` | Usage error: an unknown flag, a missing argument, a value the parser rejected, a confirmation not given. |
|
||||
| `3` | No companion device could be selected: none attached, the named one could not be opened, or the choice was ambiguous. **Nothing was transmitted.** |
|
||||
| `4` | A device was reached but the operation failed — a command error, a timeout, a link lost mid-run. Retrying is reasonable. |
|
||||
@@ -436,9 +433,8 @@ The return value is half the report, on both faces.
|
||||
|
||||
The table is printed under `meshterm --help` as well.
|
||||
|
||||
Two boundaries are worth stating because both used to sit in the wrong place. **Nothing
|
||||
transmitted is not a device failure**: a value the tool refuses before it opens the radio
|
||||
is a usage error, so a missing `--yes`, a bad `--sort` or `--category`, an unknown
|
||||
Two boundaries need stating. **Nothing transmitted is not a device failure**: a value
|
||||
the tool refuses before it opens the radio is a usage error, so a missing `--yes`, a bad `--sort` or `--category`, an unknown
|
||||
`--profile`, an outbox id that does not exist, and `tx-optimize` with no password
|
||||
available are all `2`. And **a named connection that will not open is `3`, not `4`**: a
|
||||
`--port` that is not there means no device was selected, and nothing went out.
|
||||
@@ -621,11 +617,11 @@ table has no room for.
|
||||
| Field | Type | Meaning |
|
||||
| --- | --- | --- |
|
||||
| `target` | string | What `--port` / `--ble` take, verbatim. |
|
||||
| `transport` | string | `"serial"` \| `"ble"` \| `"tcp"`. |
|
||||
| `port` | string \| null | The serial port, for a serial device. |
|
||||
| `transport` | string | `"serial"` \| `"ble"` \| `"tcp"`, or `"mock"` under `--mock`. |
|
||||
| `port` | string \| null | The serial port, for a serial device. `""` on the `--mock` row. |
|
||||
| `address` | string \| null | The Bluetooth address, for a BLE device. |
|
||||
| `label` | string | The OS's name for the device, or the confirmed node name where we have one. |
|
||||
| `hardware` | string \| null | The confirmed hardware model, else the USB vendor label. |
|
||||
| `hardware` | string \| null | The confirmed hardware model, else the USB vendor label. `""` on the `--mock` row. |
|
||||
| `meshcore` | string | `"yes"` \| `"maybe"` \| `"no"`. Not a boolean — rounding a hint up to `true` would be a lie. |
|
||||
| `confidence` | string | `"board"` \| `"bridge"` \| `"unknown"` — what a `"maybe"` was derived from. |
|
||||
| `serial_number` | string \| null | |
|
||||
@@ -634,6 +630,9 @@ table has no room for.
|
||||
| `remembered` | boolean | Whether it is the remembered default. |
|
||||
| `active` | boolean | Whether this invocation is (or would be) using it. |
|
||||
|
||||
Under `--mock` there is no scan. The list is one row for the simulator: `target`
|
||||
`"--mock"`, `transport` `"mock"`, `stable_id` `"mock:simulator"`.
|
||||
|
||||
Returns `5` when nothing is found.
|
||||
|
||||
---
|
||||
@@ -686,10 +685,11 @@ always present:
|
||||
{"name":"MockCompanion","public_key":"0000000000000000000000000000000000000000000000000000000000000000","role":"companion","model":"MeshCore Simulator","firmware":"mock mock","battery_v":4.1,"storage_used_kb":128,"storage_total_kb":1024,"clock_at":"2026-09-08T08:24:42Z","clock_drift_s":-125,"uptime_s":93784,"noise_floor_dbm":-110,"last_rssi_dbm":-62,"last_snr_db":9.5,"tx_air_s":42,"rx_air_s":360,"packets_sent":210,"packets_received":1234,"receive_errors":3}
|
||||
```
|
||||
|
||||
`role` is `"companion"` \| `"repeater"` \| `"room server"` \| `"sensor"` \| `null`. This is
|
||||
the one place the two faces disagree about absence on purpose: plain omits a key the
|
||||
firmware never answered for, JSON writes `null`, because a variable key set costs every
|
||||
consumer a lookup guard on every field.
|
||||
`role` is `"companion"` \| `"repeater"` \| `"room server"` \| `"sensor"` \| `null`, or
|
||||
`"type N"` for an advert type MeshTerm does not know. This is the one place the two faces
|
||||
disagree about absence on purpose: plain omits a key the firmware never answered for, JSON
|
||||
writes `null`, because a variable key set costs every consumer a lookup guard on every
|
||||
field.
|
||||
|
||||
`info` does not embed a `node` object — it is our own node in far more detail than the
|
||||
shape carries, and `name` / `public_key` here are its whole identity. What the radio is
|
||||
@@ -728,10 +728,12 @@ radio_bw 62.5
|
||||
radio_sf 8
|
||||
radio_cr 5
|
||||
tx_power 20
|
||||
client_repeat false
|
||||
airtime_factor 0.0
|
||||
rx_delay 0.0
|
||||
manual_add_contacts false
|
||||
autoadd_config 0
|
||||
autoadd_max_hops 0
|
||||
flood_scope ""
|
||||
adv_loc_policy 0
|
||||
multi_acks 0
|
||||
@@ -792,7 +794,7 @@ $ meshterm config advert-cadence 6 --json
|
||||
$ meshterm config sync-clock --json
|
||||
{"changes":1,"set_at":"2026-09-08T08:29:27Z","drift_s":-125}
|
||||
$ meshterm config backup node.toml --json
|
||||
{"path":"D:\\vibe\\MeshTerm\\node.toml","settings":20,"channels":0,"custom":0}
|
||||
{"path":"node.toml","settings":22,"channels":0,"custom":0}
|
||||
$ meshterm config restore node.toml --dry-run --json
|
||||
{"dry_run":true,"changes":0}
|
||||
$ meshterm config export-key --json
|
||||
@@ -805,8 +807,8 @@ $ meshterm config share --json
|
||||
|
||||
`previous` is `null` where the snapshot held no prior value; `changes` is `0` and
|
||||
`applied` is `[]` where the value already was what was asked for, and the exit stays `0`
|
||||
because the command did what it was asked. `backup`'s `path` is the file actually written
|
||||
(the plain face prints it bare, so a caller can keep it). `export-key` carries a private
|
||||
because the command did what it was asked. `backup`'s `path` is the file written, as you
|
||||
named it (the plain face prints it bare, so a caller can keep it). `export-key` carries a private
|
||||
key, exactly as the plain face does — that is what the command was asked for, and no extra
|
||||
gate is introduced here. `factory-reset --yes` answers `{"factory_reset":true}`.
|
||||
|
||||
@@ -839,8 +841,8 @@ Yagi-Repeater repeater 7m - a1 45.50190,-73.56740 a1b2c3d40000000
|
||||
answer; `--absolute` turns it into an instant. `PKTS` is how many packets passive
|
||||
monitoring has overheard.
|
||||
|
||||
**`HASH` is the token `--path` and `--to` take.** It used to have to be sliced out of `KEY`
|
||||
by hand, and getting the width wrong meant addressing a different node. It is exactly the
|
||||
**`HASH` is the token `--path` and `--to` take**, so it never has to be sliced out of `KEY`
|
||||
by hand, where getting the width wrong would address a different node. It is exactly the
|
||||
device's path-hash width. **`LOCATION`** is a fact the model always carried and no column
|
||||
had room for. `KEY` stays full and last, so it runs off the right harmlessly and is never
|
||||
elided: a truncated key is not something a caller can hand back.
|
||||
@@ -880,7 +882,6 @@ TIME NODE SNR_DB RSSI_DBM LOCATION NAME
|
||||
2026-09-08T04:26:00-04:00 b2c3d4e5 +9.5 -98 45.47680,-73.59900 Local-Repeater
|
||||
2026-09-08T04:26:00-04:00 c3d4e5f6 +4.9 -93 - Observer-Bot
|
||||
2026-09-08T04:26:00-04:00 d4e5f6a7 +7.4 -86 - Alice
|
||||
|
||||
NODE NAME PKTS MEDIAN_SNR_DB BEST_SNR_DB RSSI_DBM HEARD LOCATION
|
||||
d4e5f6a7 Alice 149 +6.9 +14.1 -93 now -
|
||||
c3d4e5f6 Observer-Bot 148 +5.7 +13.0 -108 now -
|
||||
@@ -888,9 +889,10 @@ b2c3d4e5 Local-Repeater 132 +6.7 +14.9 -102 now 45.
|
||||
a1b2c3d4 Yagi-Repeater 132 +6.0 +13.6 -90 now 45.50190,-73.56740
|
||||
```
|
||||
|
||||
Two blocks, separated by a blank line. The **stream** is a header and then a record per
|
||||
packet as it arrives; its lanes are pinned in advance, because a capture cannot measure a
|
||||
column it has not seen yet, and `TIME` is an absolute instant rather than an age — on a
|
||||
Two blocks, one straight after the other: the summary starts at its own `NODE` header
|
||||
line, with no blank line before it. The sample shows only the first four stream records.
|
||||
The **stream** is a header and then a record per packet as it arrives; its lanes are
|
||||
pinned in advance, because a capture cannot measure a column it has not seen yet, and `TIME` is an absolute instant rather than an age — on a
|
||||
live tail every row would otherwise read `now`. The **summary** is the aggregate the
|
||||
stream cannot give: a count, a median, a best per node, most recently heard first.
|
||||
|
||||
@@ -972,7 +974,7 @@ prints, honestly.
|
||||
| `lower_bound` | boolean | **JSON only.** `true` where the score is a floor — the plain face's `>=` prefix, extracted, so a consumer comparing scores need not string-match a qualifier off the front of its own data. |
|
||||
| `recorded_at` | timestamp | |
|
||||
| `version` | string | The MeshTerm version that discovered it. |
|
||||
| `path` | string | **JSON only.** The transmitted spec, comma-separated hex — what a caller re-walks with. It has no column because a route line already runs off the right. |
|
||||
| `path` | string \| null | **JSON only.** The transmitted spec, comma-separated hex — what a caller re-walks with. It has no column because a route line already runs off the right. `null` where the record stored no spec. |
|
||||
| `route` | array | The `route` shape, hop-aligned with `path`. |
|
||||
|
||||
Returns `5` and `[]` when no records match.
|
||||
@@ -1409,20 +1411,33 @@ runs `show`.
|
||||
```console
|
||||
$ meshterm preferences show
|
||||
PREFERENCE VALUE DEFAULT DESCRIPTION
|
||||
set_clock_on_connect off off Set the device clock from this computer when it connects
|
||||
trace_cooldown_s 5 5 Wait this long before transmitting again
|
||||
flood_advert_cooldown_s 60 60 Extra wait before another mesh-wide advert
|
||||
direct_message_soft_retries 0 0 Times to resend a message that gets no reply
|
||||
tx_opt_min 18 18 Weakest power it will try
|
||||
tx_opt_max 28 28 Strongest power it will try
|
||||
tx_snr_tolerance_db 1 1 Signals this close are a tie, so less power wins
|
||||
watch_silence_hours 12 12 Warn when a watched node goes quiet this long
|
||||
watch_alerts_kept 200 200 How many past alerts to keep
|
||||
map_view_fraction 0.5 0.5 Share of nodes to fit on screen; 1 shows them all
|
||||
basemap_tilejson_url https://tiles.openfreemap.org/planet https://tiles.openfreemap.org/planet Where map images come from (next launch)
|
||||
history_days 365 365 Older ones are deleted; 0 keeps everything
|
||||
chat_history_limit 200 200 Old messages to load when you open a chat
|
||||
courier_history_kept 100 100 Finished outbox messages to keep
|
||||
cli_time_format relative relative Whether the command line prints ages or timestamps
|
||||
fast_render on on Faster screen updates; turn off if it looks wrong (next launch)
|
||||
full_width auto auto Use the extra column some terminals hide
|
||||
color_depth auto auto How many colours to send this terminal (next launch)
|
||||
console_setup auto auto Move to a better terminal when this console can't draw MeshTerm
|
||||
console_font 6x12 6x12 Bigger text, or more rows on the handheld's panel
|
||||
log_level WARNING WARNING How much MeshTerm writes to its log file (next launch)
|
||||
```
|
||||
|
||||
**`DESCRIPTION` is back**, because a key's name is not its meaning and the alternative was
|
||||
opening the menu to find out what one does. Values print in the form `preferences set`
|
||||
accepts back — no unit suffix on a number, `on`/`off` for a boolean. Where `VALUE` differs
|
||||
from `DEFAULT`, this install has an override.
|
||||
**`DESCRIPTION`** says what each preference does, because a key's name is not its
|
||||
meaning. Values print in the form `preferences set` accepts back — no unit suffix on a
|
||||
number, `on`/`off` for a boolean. Where `VALUE` differs from `DEFAULT`, this install has an
|
||||
override.
|
||||
|
||||
Overrides live in `preferences.toml` in [MeshTerm's state
|
||||
directory](#where-meshterm-keeps-its-state), which lists only what you have changed; delete
|
||||
@@ -1488,6 +1503,10 @@ three or four questions that otherwise get asked one at a time in an issue threa
|
||||
person who hit the bug is usually the one least able to answer them — half of it is
|
||||
resolved at boot and shown on no screen.
|
||||
|
||||
This sample is the one exception to [About the examples](#about-the-examples): it is an
|
||||
illustrative report from a real radio over Bluetooth, because the simulator's report says
|
||||
little. The field names and layout are what the command prints; the values are examples.
|
||||
|
||||
```console
|
||||
$ meshterm diagnostics
|
||||
meshterm 0.9.0
|
||||
@@ -1522,22 +1541,30 @@ radio_cr 5
|
||||
tx_power_dbm 20
|
||||
error -
|
||||
|
||||
config_dir C:\Users\jp\.meshterm
|
||||
config_dir C:\Users\you\.meshterm
|
||||
db_size_kb 41280
|
||||
log_level WARNING
|
||||
log_level DEBUG
|
||||
log_size_kb 96
|
||||
runs_failed 3
|
||||
first_heard 8mo
|
||||
last_heard now
|
||||
first_heard 2026-01-14T19:42:10-05:00
|
||||
last_heard 2026-09-21T11:03:00-04:00
|
||||
|
||||
TABLE ROWS
|
||||
observations 418203
|
||||
runs 912
|
||||
traces 47
|
||||
TABLE ROWS
|
||||
app_state 4
|
||||
discovered_paths 1287
|
||||
messages 3316
|
||||
neighbour_reports 214
|
||||
observations 418203
|
||||
path_candidates 96
|
||||
runs 912
|
||||
schema_meta 1
|
||||
trace_hops 233
|
||||
traces 47
|
||||
tx_samples 68
|
||||
|
||||
PREFERENCE VALUE
|
||||
log_level DEBUG
|
||||
map_style terrain
|
||||
PREFERENCE VALUE
|
||||
log_level DEBUG
|
||||
history_days 730
|
||||
```
|
||||
|
||||
The seven groups are the page's seven sections — build, host, terminal, radio, storage,
|
||||
@@ -1566,7 +1593,7 @@ Under `--json`, the five fact blocks merge into one flat object and the two list
|
||||
a key of their own:
|
||||
|
||||
```json
|
||||
{"meshterm":"0.9.0","install":"frozen","os":"Windows 11","…":"…","tables":[{"table":"observations","rows":418203}],"preferences":[{"preference":"log_level","value":"DEBUG"}]}
|
||||
{"meshterm":"0.9.0","install":"frozen","os":"Windows 11","…":"…","tables":[{"table":"app_state","rows":4},"…"],"preferences":[{"preference":"log_level","value":"DEBUG"},{"preference":"history_days","value":"730"}]}
|
||||
```
|
||||
|
||||
**`--out PATH` writes it to a file instead of printing it**, and the answer becomes the
|
||||
@@ -1576,7 +1603,7 @@ wants to be told where it is rather than handed the contents they just redirecte
|
||||
```console
|
||||
$ meshterm diagnostics --out meshterm-diagnostics.md
|
||||
✓ diagnostics written — attach it to the report.
|
||||
/home/jp/meshterm-diagnostics.md
|
||||
meshterm-diagnostics.md
|
||||
```
|
||||
|
||||
**The file is markdown**, whichever face the run was printing, because an issue tracker
|
||||
|
||||
@@ -28,13 +28,12 @@ Write a config file only to give your hardware stable aliases.
|
||||
Copy [`config.example.toml`](../config.example.toml) to `~/.meshterm/config.toml`:
|
||||
|
||||
```toml
|
||||
default_profile = "s3"
|
||||
# default_profile = "s3" # uncomment and name your own profile to make it the default
|
||||
connect_on_start = true # false opens the radio link lazily instead of at launch
|
||||
|
||||
[profiles.s3]
|
||||
port = "COM5"
|
||||
baudrate = 115200
|
||||
default_tx_power = 20
|
||||
description = "XIAO ESP32-S3 + Wio SX1262 serial companion"
|
||||
|
||||
# A Bluetooth LE companion: give it an `address` instead of a `port`.
|
||||
@@ -58,6 +57,7 @@ database alone; the rest stays where it was. A `--mock` run that names neither w
|
||||
it. [`docs/cli.md`](cli.md#where-meshterm-keeps-its-state)
|
||||
lists every file.
|
||||
|
||||
Timestamps are stored as UTC and rendered in your local time. History older than the
|
||||
`history_days` preference is pruned once at session start.
|
||||
Timestamps are stored as UTC and rendered in your local time. Heard packets older than the
|
||||
`history_days` preference are deleted when monitoring starts: once in each menu session,
|
||||
and at the start of each `meshterm monitor` run. Nothing else is pruned.
|
||||
|
||||
+10
-7
@@ -37,8 +37,9 @@ meshterm courier queue Alice "ping me when you're back" --at 18:30
|
||||
meshterm courier list # the outbox — waiting and finished
|
||||
meshterm courier send 3 # force one delivery attempt now
|
||||
|
||||
# Remote repeater admin (one transmission per invocation)
|
||||
meshterm repeater-admin Bravo-Repeater "get name"
|
||||
# Remote repeater admin (one transmission per invocation). --password is needed
|
||||
# until an interactive login has stored one.
|
||||
meshterm repeater-admin Bravo-Repeater "get name" --password YOUR-ADMIN-PASSWORD
|
||||
|
||||
# Device configuration: view, set, back up, restore
|
||||
meshterm config # show all current settings, one `key value` per line
|
||||
@@ -54,16 +55,18 @@ meshterm monitor --seconds 60
|
||||
```
|
||||
|
||||
Global options — `--profile/-p`, `--port`, `--ble`, `--ble-pin`, `--tcp`, `--mock`,
|
||||
`--db`, `--json`, `--absolute`, `--quiet/-q` — may be typed **before or after** the
|
||||
subcommand: `meshterm contacts --json` and `meshterm --json contacts` are the same run.
|
||||
`--db`, `--json`, `--absolute`, `--quiet/-q`, `--platform` — may be typed **before or
|
||||
after** the subcommand: `meshterm contacts --json` and `meshterm --json contacts` are the
|
||||
same run.
|
||||
|
||||
## Two output faces
|
||||
|
||||
*(The short version — [`docs/cli.md`](cli.md) has the whole of it.)*
|
||||
|
||||
The **plain face** is for a person at a prompt. It prints like a standard Unix utility —
|
||||
no colour, no borders, one record per line, nothing wrapped — and it is allowed to be
|
||||
comfortable about it: listings are `ps`-style aligned records with **bare names**
|
||||
no colour, no borders, one record per line, nothing wrapped except the four written
|
||||
pages (`about`, `about-author`, `discord`, `support`), which wrap at 72 cells — and it is
|
||||
allowed to be comfortable about it: listings are `ps`-style aligned records with **bare names**
|
||||
(alignment is the delimiter), times are **relative ages** (`now`, `5m`, `never`), and a
|
||||
route is drawn with arrows — `MockCompanion (00) → Yagi-Repeater (a1) → Alice (d4)`.
|
||||
`--absolute` swaps every age back for an ISO-8601 instant. A *path*, the spec `--path`
|
||||
@@ -98,7 +101,7 @@ without counting output lines.
|
||||
|
||||
```bash
|
||||
if meshterm contacts > contacts.txt; then
|
||||
echo "$(wc -l < contacts.txt) contacts"
|
||||
echo "$(($(wc -l < contacts.txt) - 1)) contacts" # minus the header
|
||||
elif [ $? -eq 5 ]; then
|
||||
echo "no contacts yet"
|
||||
fi
|
||||
|
||||
+5
-5
@@ -26,7 +26,7 @@ Every interactive screen is listed here with its scripted equivalent, where one
|
||||
| **📊 Dashboard** | The live mesh overview: a two-hour all-packet activity chart with a pulse line, session traffic tallies by packet class, and window RF health beside the radio's own live numbers. Repaints every second. | — |
|
||||
| **📰 Live feed** | Every packet as it arrives, newest first: time, what the frame *is* (its parsed payload class), and what it is *about* — the node for an advert, the channel for a channel text, sender → recipient for a direct message or a request, the tag for a trace — with reception quality beside it. Enter opens any row in the packet viewer, route graph and all. | — |
|
||||
| **🚨 Watchtower** | A passive sentinel over the nodes you star: silence alarms when a watched node goes quiet, SNR-sag warnings when reception degrades, recovery notes when it returns, and a heads-up when a never-before-seen node appears. Runs in the background all session; unacked alerts show as a header badge. | — |
|
||||
| **⏳ Time machine** | Everything the recorder ever heard, as braille charts: reception volume, the median-SNR band, hour-of-day rhythm, packets and nodes per day, and first-ever arrivals — over a switchable 24h / 7d / 30d / all-time window, per node or mesh-wide. | — |
|
||||
| **⏳ Time machine** | Everything the recorder ever heard, as braille charts: reception volume, the median-SNR band, hour-of-day rhythm, packets and nodes per day, and first-ever arrivals — over a switchable 24h / 7d / 30d / all-time window (on the PicoCalc the windows stop at 30d), per node or mesh-wide. | — |
|
||||
| **🎧 Monitor** | Passive recording is always on in the app. On the CLI, capture a bounded foreground window, tailing each overheard packet and summarising when it ends. It transmits nothing — it only listens. | `meshterm monitor --seconds 60` |
|
||||
|
||||
## 🧭 Explore — where the nodes are and how they reach each other
|
||||
@@ -44,16 +44,16 @@ Every interactive screen is listed here with its scripted equivalent, where one
|
||||
| Feature | What it does | Scripted |
|
||||
| --- | --- | --- |
|
||||
| **📋 Device info** | The connected companion's identity and full radio configuration at a glance. | `meshterm info` |
|
||||
| **🔧 Device config** | Every setting the companion firmware exposes — name, radio, client repeat, auto-add, telemetry, custom variables — *staged* for review and applied in place, plus the operations on the box itself: clock sync, TOML backup/restore, the identity key, reboot, and factory reset, each acting the moment it's confirmed, with destructive ops gated. Laid out like Repeater admin, so the radio in your hand and one over the mesh are configured the same way. | `meshterm config` / `config set <key> <value>` / `config backup` / `reboot` / … |
|
||||
| **🔧 Device config** | Every setting the companion firmware exposes — name, radio, client repeat, auto-add, telemetry, custom variables — *staged* for review and applied in place, plus the operations on the box itself: clock sync, TOML backup/restore, the identity key, reboot, and factory reset, each acting the moment it's confirmed, with destructive ops gated. Laid out like Repeater admin, so the radio in your hand and one over the mesh are configured the same way. | `meshterm config` / `config set <key> <value>` / `config backup` / `config reboot` / … |
|
||||
| **📡 Send advert** | Announce this node to the mesh — a zero-hop or flood advertisement, or share this node's contact card as a QR code. | `meshterm config advert` / `config share` |
|
||||
| **🔌 Device discovery** | Enumerate serial *and* Bluetooth LE companions, pick one interactively (or auto-select the only one present), add a network (TCP) companion by host:port, and remember the last good default. A dropped link is detected live and offers to reconnect. | `meshterm devices` |
|
||||
| **🔌 Devices** | Not a menu screen. The companion is picked on the startup splash, which enumerates serial *and* Bluetooth LE companions (or auto-selects the only one present), adds a network (TCP) companion by host:port, and remembers the last good default. A dropped link is detected live and offers to reconnect. `meshterm devices` lists what discovery finds. | `meshterm devices` |
|
||||
|
||||
## 🗼 Other nodes — someone else's radio, over the mesh
|
||||
|
||||
| Feature | What it does | Scripted |
|
||||
| --- | --- | --- |
|
||||
| **🗼 Repeater admin** | Set up remote repeaters and room servers over the mesh: log in (remembered or prompted password), then a config-style editor speaking the node's text CLI — including repeater-only knobs (TX delay, airtime factor, advert intervals) — plus one-shot actions and a readline remote command line. | `meshterm repeater-admin <node> <command…>` |
|
||||
| **📶 TX optimize** | Sweep a remote node's transmit power live — coarse, then refine, then verify — watch each level land, and decide whether to apply the winner. | `meshterm tx-optimize --path … [--apply]` |
|
||||
| **📶 TX optimize** | Sweep a remote node's transmit power live — coarse, then refine, then verify — watch each level land, and decide whether to apply the winner. The scripted form applies the winner unless told not to. | `meshterm tx-optimize --path … [--no-apply]` |
|
||||
|
||||
## ⚙ This app — the program in front of you
|
||||
|
||||
@@ -63,7 +63,7 @@ pages close it.
|
||||
|
||||
| Feature | What it does | Scripted |
|
||||
| --- | --- | --- |
|
||||
| **⚙ Preferences** | How MeshTerm behaves — startup, sending, history, map framing. Grouped and staged, saved by one action at the bottom, and written to `preferences.toml` as only the values you changed. [Configuring MeshTerm](configuration.md) has the detail. | `meshterm preferences show / set / reset` |
|
||||
| **⚙ Preferences** | How MeshTerm behaves, in eight groups: Device, Sending, TX optimize, Watchtower, Map, History, Display and Diagnostics. Grouped and staged, saved by one action at the bottom, and written to `preferences.toml` as only the values you changed. [Configuring MeshTerm](configuration.md) has the detail. | `meshterm preferences show / set / reset` |
|
||||
| **🩺 Diagnostics** | Everything a bug report opens with, in one block: which build this is and how it was installed, the OS, the terminal and its size, the boot-time verdicts that show on no screen (icons, powerline, platform flavour and why), the radio and its link, and how much history is stored. Nothing private — no keys, passwords, positions or contact names; the mesh is described as per-table counts and the span they cover. `s` saves it beside the log for attaching. | `meshterm diagnostics [--out PATH]` |
|
||||
| **📖 About MeshTerm** | What MeshTerm is, where it came from, and the terms it ships under — including the map and font credits and the licence URL. | `meshterm about` |
|
||||
| **👤 About the author** | The person behind MeshTerm, on the mesh and off it. | `meshterm about-author` |
|
||||
|
||||
+3
-3
@@ -36,10 +36,10 @@ directly, or a pump in front of it, never both.
|
||||
| File | Runs on | What it does |
|
||||
| --- | --- | --- |
|
||||
| [`picocalc/calculinux-setup.sh`](../scripts/picocalc/calculinux-setup.sh) | the Lyra (root) | One-time bring-up: python packages, the Wi-Fi boot-scan kick, a boot clock sync (there is no RTC), the deploy user, the checkout, the venv and `pip install -e .`, the login PATH, and the console font. Idempotent. |
|
||||
| [`picocalc/calculinux-console-font-6x12.sh`](../scripts/picocalc/calculinux-console-font-6x12.sh) | the Lyra (root) | Just the console font: builds, installs and persists the 512-glyph **meshterm** PSF (braille, node marks, rounded frame corners, the list cursor) and restores the stock 16-slot palette. Calls the 6×8 build below when it sits alongside. Run it alone after a MeshTerm update. |
|
||||
| [`picocalc/calculinux-console-font-6x12.sh`](../scripts/picocalc/calculinux-console-font-6x12.sh) | the Lyra (root) | Just the console font: builds, installs and persists the 512-glyph **meshterm** PSF (braille, node marks, rounded frame corners, the list cursor) and restores the stock 16-slot palette. Calls the 6×8 build below when it sits alongside. Run it alone after a MeshTerm update, from the pulled checkout (`/home/meshterm/MeshTerm/scripts/picocalc/`) rather than the copy made at install time. |
|
||||
| [`picocalc/calculinux-console-font-6x8.sh`](../scripts/picocalc/calculinux-console-font-6x8.sh) | the Lyra (root) | The shorter-cell companion font, **meshterm8** (6×8 → 53×40), for anyone who wants more rows than the 6×12 default gives. Its base bitmap is the kernel's `font_6x8`, so this one file and the PSF it builds are **GPL-2.0-only** ([`LICENSE.GPL-2.0`](../scripts/picocalc/LICENSE.GPL-2.0) sits beside it); it reads the donor/alias/keeper tables out of the script above rather than keeping a second copy. Pick between the two fonts from MeshTerm's Preferences page. |
|
||||
| [`picocalc/calculinux-wifi-set.sh`](../scripts/picocalc/calculinux-wifi-set.sh) | the Lyra (sudo) | Interactive Wi-Fi join: prompts for an SSID and passphrase, writes iwd's credentials, connects now. This is how a network *becomes* known to the boot kick. |
|
||||
| [`picocalc/calculinux-radio-bridge.sh`](../scripts/picocalc/calculinux-radio-bridge.sh) | the Lyra (root) | **Unfinished, unsupported.** An early UART-to-TCP pump, superseded by `xiao-radio/lyra-setup.sh`; its header describes routing it does not contain. See the manual before reading it. |
|
||||
| [`picocalc/calculinux-radio-bridge.sh`](../scripts/picocalc/calculinux-radio-bridge.sh) | the Lyra (root) | **Unfinished, unsupported.** An early UART-to-TCP pump: it serves `/dev/ttyS1` on TCP port 5000 and writes a `radio` TCP profile. It does not route UART1 to the header pads. Superseded by `xiao-radio/lyra-setup.sh`, which does the routing and points MeshTerm at the serial port directly. |
|
||||
| [`picocalc/xiao-radio/`](../scripts/picocalc/xiao-radio/) | see below | Everything for the XIAO nRF52840 + Wio-SX1262 radio wired to the Lyra's UART1; its [bench card](../scripts/picocalc/xiao-radio/README.md) has the wiring table. The firmware is MeshCore, MIT-licensed — [`LICENSE.MeshCore`](../scripts/picocalc/xiao-radio/LICENSE.MeshCore) sits beside the patch. |
|
||||
| [`xiao-radio/build-firmware.sh`](../scripts/picocalc/xiao-radio/build-firmware.sh) | dev machine | Clones and patches MeshCore, builds the `Xiao_nrf52_companion_radio_serial` environment, emits the `.uf2`. |
|
||||
| [`xiao-radio/flash.py`](../scripts/picocalc/xiao-radio/flash.py) | dev machine | Flashes the `.uf2` to the XIAO over its UF2 bootloader, refusing the wrong board or SoftDevice; prints the serial-DFU command when the bootloader offers no drive. |
|
||||
@@ -54,7 +54,7 @@ MeshTerm resolves one frozen **platform** at boot and draws everything through i
|
||||
**regular** platform is a desktop or ssh terminal: 72 readable columns, truecolour, emoji,
|
||||
a footer hint line. The **picocalc** platform is a framebuffer console: 53 columns, no
|
||||
emoji, an F-key lane instead of a hint line, and sixteen colour slots rather than a colour
|
||||
space — nothing loses its colour there, the node hue and the recency heat gradient
|
||||
space. Nothing loses its colour there: the node hue and the recency heat gradient
|
||||
quantise to those slots instead. It is detected from the device tree on the Lyra, and
|
||||
`--platform picocalc` or `MESHTERM_PLATFORM=picocalc` forces it anywhere, which is how you
|
||||
preview the handheld layout on a desktop:
|
||||
|
||||
+83
-57
@@ -65,9 +65,9 @@ a radio in the meantime.
|
||||
| Item | Product / what to search for | Approx. price | Link | Note |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| PicoCalc kit | ClockworkPi PicoCalc | $89 | [clockworkpi.com/product-page/picocalc](https://www.clockworkpi.com/product-page/picocalc) | Comes with a Raspberry Pi Pico 1H, screen, keyboard, shell, hex key and a 32 GB SD card. **18650 batteries are not included.** |
|
||||
| Luckfox Lyra | "Luckfox Lyra 128MB, pre-soldered header, no NAND" | $20–25 | [luckfox.com/Luckfox-Lyra](https://www.luckfox.com/Luckfox-Lyra) | Buy the **plain 128 MB RAM, Pico-form-factor** variant, **with the header pre-soldered**. See the note below — this is the one part of the list where the wrong SKU won't work. |
|
||||
| Luckfox Lyra | "Luckfox Lyra 128MB, pre-soldered header, no NAND" | $20–25 | [luckfox.com/Luckfox-Lyra](https://www.luckfox.com/Luckfox-Lyra) | Buy the **plain 128 MB RAM, Pico-form-factor** variant, **with the header pre-soldered**. Other RAM sizes have incompatible pinouts, so this is the one part of the list where the wrong SKU won't work. |
|
||||
| microSD card | 16 GB+, Class 10 or better | $6–10 | — | The PicoCalc's stock 32 GB card works fine — it's more than the 8 GB minimum. You can reuse it instead of buying a new one. |
|
||||
| Two 18650 batteries | e.g. Samsung 30Q, Molicel P26A, Sony VTC6 (examples, not endorsements) | $10–20 | — | **Unprotected**, flat-top or button-top, Ø18 × 65–69 mm. See [the battery note](#a-note-on-batteries) below. |
|
||||
| An 18650 battery | e.g. Samsung 30Q, Molicel P26A, Sony VTC6 (examples, not endorsements) | $5–10 | — | **Unprotected**, flat-top or button-top, Ø18 × 65–69 mm. One is enough to run; a second is optional (below). See [the battery note](#a-note-on-batteries) below. |
|
||||
| USB Wi-Fi dongle | TP-Link TL-WN725N (an RTL8188EU nano dongle), or search the **chipset name**: RTL8192CU, R8712U, RTL8188EU | $5–10 | [amazon.ca/dp/B008IFXQFU](https://www.amazon.ca/dp/B008IFXQFU) | The TL-WN725N is the dongle this guide was built with. Must run at **3.3 V** — see [Step 3](#step-3--attach-the-wi-fi-dongle). Only needed for setup and updates; MeshTerm itself runs offline. |
|
||||
| MX1.25 4-pin pigtail | "MX1.25 4P cable with leads" (a pack of pre-crimped pigtails, 10–15 cm) | $2–4 | — | One end of the DIY USB lead in [Step 3](#step-3--attach-the-wi-fi-dongle). Pre-crimped, because MX1.25 contacts need a crimper you don't otherwise own. |
|
||||
| USB-A female socket | "USB 2.0 type A female socket, solder / through-hole" | $2–3 | — | The other end of the DIY lead. A ready-made [MX1.25 4P to USB-A cable](https://spotpear.com/shop/Luckfox-Lyra-MX1.25-4P-To-USB-A-Cable.html) (about $1, 30 cm) works too, but it is a lot of cable to fold into the shell. |
|
||||
@@ -101,7 +101,7 @@ a radio in the meantime.
|
||||
| Foam tape | To secure the XIAO board inside the shell once it's wired in. |
|
||||
|
||||
Approximate total: **$130–150** for the machine and radio together, before batteries — most
|
||||
of that is the two boards ($89 + ~$22) and the radio kit ($13.49).
|
||||
of that is the PicoCalc kit ($89), the Lyra (~$22) and the radio kit ($13.49).
|
||||
|
||||
**What you do NOT need:**
|
||||
|
||||
@@ -213,8 +213,8 @@ machine it describes. Read this section before you open the shell.
|
||||
Follow ClockworkPi's own
|
||||
[assembly guidelines](https://github.com/clockworkpi/PicoCalc/blob/master/Clockwork_PicoCalc_Assembly_Guidelines.pdf)
|
||||
(a PDF in the [PicoCalc repository](https://github.com/clockworkpi/PicoCalc), which also
|
||||
has a wiki) to put the kit together: mainboard, screen, keyboard, speakers and shell. Insert your two
|
||||
18650 batteries, watching the `+`/`-` marks in the battery compartment.
|
||||
has a wiki) to put the kit together: mainboard, screen, keyboard, speakers and shell. Insert your 18650
|
||||
battery (or two), watching the `+`/`-` marks in the battery compartment.
|
||||
|
||||
⚠ Two of the warnings in [Three ways to break it](#three-ways-to-break-it) apply here: tape
|
||||
the screen's edges with Kapton before you close the shell and check it sits square, and
|
||||
@@ -311,14 +311,17 @@ Don't power the device on yet — Wi-Fi is set up later, once Calculinux is inst
|
||||
|
||||
### Step 4 — Write the image to the microSD
|
||||
|
||||
On your PC, download the latest `calculinux-image-luckfox-lyra.rootfs.wic.gz` from the
|
||||
[Calculinux releases page](https://github.com/Calculinux/meta-calculinux/releases).
|
||||
On your PC, download `calculinux-image-luckfox-lyra.rootfs-<timestamp>.wic.gz` from the
|
||||
newest release on the
|
||||
[Calculinux releases page](https://github.com/Calculinux/meta-calculinux/releases). Every
|
||||
Calculinux release is marked **Pre-release**, so there is no "Latest" badge to follow; take
|
||||
the newest pre-release.
|
||||
|
||||
Decompress it:
|
||||
|
||||
```bash
|
||||
# on the PC
|
||||
gunzip calculinux-image-luckfox-lyra.rootfs.wic.gz
|
||||
gunzip calculinux-image-luckfox-lyra.rootfs-*.wic.gz
|
||||
```
|
||||
|
||||
(The Calculinux installation page mentions `unxz`, but the file is a `.gz`, so use
|
||||
@@ -331,11 +334,11 @@ Write the resulting `.wic` file to your microSD card. Three options:
|
||||
- **`dd`**, on Linux/macOS. Check the device name first — writing to the wrong device
|
||||
destroys its contents:
|
||||
|
||||
```bash
|
||||
# on the PC
|
||||
lsblk # find your SD card's device, e.g. /dev/sdb
|
||||
sudo dd if=calculinux-image-luckfox-lyra.rootfs.wic of=/dev/sdX bs=4M status=progress conv=fsync
|
||||
```
|
||||
```bash
|
||||
# on the PC
|
||||
lsblk # find your SD card's device, e.g. /dev/sdb
|
||||
sudo dd if=calculinux-image-luckfox-lyra.rootfs-*.wic of=/dev/sdX bs=4M status=progress conv=fsync
|
||||
```
|
||||
|
||||
- **Rufus**, on Windows — select the device and the image, choose the **MBR** partition
|
||||
scheme, and start.
|
||||
@@ -345,6 +348,9 @@ This erases everything already on the card. Once it finishes, eject it and put i
|
||||
from its own slot; the front slot is only reachable once MeshTerm (or anything else) is
|
||||
already running on Linux.
|
||||
|
||||
Leave the front slot **empty** for the first boot, as Calculinux's own instructions warn: a
|
||||
second card there with duplicate partition labels leaves the system read-only.
|
||||
|
||||
### Step 5 — First boot
|
||||
|
||||
With the card in the Lyra, power the PicoCalc on. Give it 30–60 seconds — the first boot is
|
||||
@@ -417,30 +423,29 @@ the network, so this is a one-time step; to change networks later, run `uwific`
|
||||
### Step 8 — Copy the setup scripts to the device
|
||||
|
||||
You need this repository's `scripts/` directory on the Lyra — its `picocalc/` folder is the
|
||||
part the Lyra runs. Three ways to get it there, in order of ease:
|
||||
part the Lyra runs. Two ways to get it there, once Wi-Fi is up:
|
||||
|
||||
- **`scp` from your PC**, once Wi-Fi is up. Find the Lyra's IP address with `ip addr show
|
||||
wlan0` on the device, then from your PC:
|
||||
- **`scp` from your PC**. Find the Lyra's IP address with `ip addr show wlan0` on the
|
||||
device, then from your PC:
|
||||
|
||||
```bash
|
||||
# on the PC, from your MeshTerm checkout
|
||||
scp -r scripts root@<lyra-ip>:/root/
|
||||
```
|
||||
```bash
|
||||
# on the PC, from your MeshTerm checkout
|
||||
scp -r scripts root@<lyra-ip>:/root/
|
||||
```
|
||||
|
||||
If root is refused over SSH, copy as the `pico` user (password `calc`) instead, then
|
||||
move the directory as root on the device:
|
||||
|
||||
```bash
|
||||
# on the PC
|
||||
scp -r scripts pico@<lyra-ip>:/home/pico/
|
||||
# on the PicoCalc, as root
|
||||
mv /home/pico/scripts /root/
|
||||
```
|
||||
```bash
|
||||
# on the PC
|
||||
scp -r scripts pico@<lyra-ip>:/home/pico/
|
||||
# on the PicoCalc, as root
|
||||
mv /home/pico/scripts /root/
|
||||
```
|
||||
|
||||
- **The microSD card.** Pull the card, copy `scripts/` onto it from your PC's card reader,
|
||||
put it back.
|
||||
- **`git clone` on the device.** Only once `git` is installed, and the setup script is what
|
||||
installs it — so this is a route for later updates, not the first copy.
|
||||
- **`git clone` on the device.** `git` ships in the Calculinux base image, so as root you
|
||||
can run `git clone https://github.com/jpmartineau/MeshTerm` and use the `scripts/`
|
||||
folder inside the clone.
|
||||
|
||||
`scp` is the recommended route.
|
||||
|
||||
@@ -452,30 +457,40 @@ cd scripts/picocalc
|
||||
sh calculinux-setup.sh
|
||||
```
|
||||
|
||||
It's idempotent — safe to re-run — and it checks before it acts. Two things it can't figure
|
||||
out on its own, both covered by environment variables read at the top of the script:
|
||||
It's idempotent — safe to re-run — and it checks before it acts. It reads these
|
||||
environment variables at the top of the script:
|
||||
|
||||
| Knob | Default | Effect |
|
||||
| --- | --- | --- |
|
||||
| `DEPLOY_USER` | `meshterm` | the login MeshTerm runs under |
|
||||
| `TIMEZONE` | `America/Toronto` | any IANA zone |
|
||||
| `TIMEZONE` | `America/Toronto` | any IANA zone. Set it if you are not on Eastern time. |
|
||||
| `REPO_URL` | the project's HTTPS URL | cloned when there's no deploy key |
|
||||
| `REPO_SSH` | the project's SSH URL | cloned when there is one |
|
||||
| `KEY_PATH` | `/home/$DEPLOY_USER/.ssh/id_ed25519` | a read-only GitHub deploy key, if you want SSH instead of HTTPS |
|
||||
| `WIFI_SSID`, `WIFI_PSK` | unset | set both and the script writes `iwd`'s credentials for that network, as an alternative to Step 7 |
|
||||
|
||||
You don't need to set any of these for a normal install — the defaults clone MeshTerm's
|
||||
public repository over plain HTTPS, which needs no credential at all.
|
||||
The defaults clone MeshTerm's public repository over plain HTTPS, which needs no credential
|
||||
at all. The one you are likely to need is `TIMEZONE`, if you live outside Eastern time:
|
||||
|
||||
```bash
|
||||
# on the PicoCalc, as root
|
||||
TIMEZONE=America/Vancouver sh calculinux-setup.sh
|
||||
```
|
||||
|
||||
The script installs only the Americas time-zone data, so a zone elsewhere may not take. If
|
||||
it cannot set the zone, it warns and the clock stays on UTC.
|
||||
|
||||
What it does, one line per phase:
|
||||
|
||||
- **opkg packages** — installs `python3-modules`, `python3-pip`, `git`, `kbd`, because
|
||||
Calculinux ships a stripped Python missing `pip`, `venv` and several stdlib modules.
|
||||
- **opkg packages** — installs `python3-modules` and `python3-pip` (and `git` and `kbd`,
|
||||
if the image lacks them), because Calculinux ships a stripped Python missing `pip`,
|
||||
`venv` and several stdlib modules.
|
||||
- **Wi-Fi kick** — installs a boot-time service that re-scans until the dongle joins the
|
||||
network `iwd` already knows, because on a cold boot the dongle's firmware finishes
|
||||
loading after `iwd`'s first scan and the link would otherwise never come up.
|
||||
- **Time sync** — installs a boot-time service that sets the clock over the network, since
|
||||
this board has no battery-backed real-time clock.
|
||||
- **Timezone** — sets `$TIMEZONE` (Eastern by default).
|
||||
- **Timezone** — sets `$TIMEZONE` (`America/Toronto` by default).
|
||||
- **Deploy user** — creates the `meshterm` login and puts it in the groups it needs.
|
||||
- **Clone** — checks out MeshTerm to `/home/meshterm/MeshTerm`.
|
||||
- **venv and install** — builds a Python virtual environment and `pip install -e .`s
|
||||
@@ -493,9 +508,10 @@ password yet, so set one first:
|
||||
passwd meshterm
|
||||
```
|
||||
|
||||
> **With no Wi-Fi dongle attached, the next boot takes about six minutes** to get past the
|
||||
> Wi-Fi kick, which keeps trying before it gives up. Nothing is broken. If the device is
|
||||
> going to live offline, see [Day-to-day](#day-to-day) for how to switch the kick off.
|
||||
> **With no Wi-Fi dongle attached, the next boot can take up to about eleven minutes.**
|
||||
> The Wi-Fi kick keeps trying for about six before it gives up, and the time sync then
|
||||
> waits up to five more for a network route. Nothing is broken. If the device is going to
|
||||
> live offline, see [Day-to-day](#day-to-day) for how to switch both off.
|
||||
|
||||
### Step 10 — Log in as meshterm
|
||||
|
||||
@@ -521,7 +537,7 @@ Then look at the whole visual language on one card:
|
||||
meshterm specimen
|
||||
```
|
||||
|
||||
There are two console fonts available — a 6×12 one (53×26 rows) and a 6×8 one (53×40 rows,
|
||||
There are two console fonts available — a 6×12 one (53 × 26) and a 6×8 one (53 × 40,
|
||||
more rows but no Cyrillic glyphs). Try both from *Preferences → Display → Console font* —
|
||||
picking one previews it immediately, and the screen repaints at the new row count so you can
|
||||
see the choice before you keep it.
|
||||
@@ -776,8 +792,9 @@ default_tx_power = 22
|
||||
description = "XIAO nRF52840 + SX1262 via Lyra UART1 on GP4/GP5"
|
||||
```
|
||||
|
||||
If a `config.toml` already exists, it prints those lines instead of touching your file —
|
||||
paste them in yourself.
|
||||
If a `config.toml` already exists, it leaves your file untouched and prints only the
|
||||
`default_profile` line, the `[profiles.picocalc]` heading and the `port`. Copy the whole
|
||||
block above into your file yourself.
|
||||
|
||||
### Step 16 — Run it
|
||||
|
||||
@@ -788,7 +805,8 @@ Log out and back in as `meshterm` (so the `dialout` group membership takes effec
|
||||
meshterm
|
||||
```
|
||||
|
||||
Because `default_profile` is set, a bare `meshterm` connects straight to the radio. You
|
||||
A bare `meshterm` opens on the **Select a companion device** splash, with the `picocalc`
|
||||
profile listed as a row; pick it. To skip the splash, run `meshterm -p picocalc`. You
|
||||
should see your node come up under whatever name the firmware advertises — both the device
|
||||
page and the dashboard header show it.
|
||||
|
||||
@@ -815,39 +833,47 @@ through the Lyra's own USB-C at the back — see
|
||||
sudo poweroff
|
||||
```
|
||||
|
||||
**Updating MeshTerm.** Either re-run the setup script from root (it pulls the repository,
|
||||
reinstalls, and rebuilds the console font):
|
||||
**Updating MeshTerm.** The copy of `scripts/` you made in Step 8 goes stale as soon as
|
||||
the checkout moves on, so run the scripts inside the checkout instead. Either pull and
|
||||
re-run the setup script from root (it reinstalls and rebuilds the console font):
|
||||
|
||||
```bash
|
||||
# on the PicoCalc, as root
|
||||
sh calculinux-setup.sh
|
||||
su - meshterm -c 'git -C ~/MeshTerm pull'
|
||||
sh /home/meshterm/MeshTerm/scripts/picocalc/calculinux-setup.sh
|
||||
```
|
||||
|
||||
or, as the `meshterm` user, do just the update:
|
||||
|
||||
```bash
|
||||
# on the PicoCalc, as meshterm
|
||||
cd ~/MeshTerm && git pull && .venv/bin/pip install -e .
|
||||
cd ~/MeshTerm && git pull && TMPDIR=$HOME/tmp .venv/bin/pip install -e .
|
||||
```
|
||||
|
||||
If an update adds new glyphs to the console font, rebuild it on its own afterwards:
|
||||
|
||||
```bash
|
||||
# on the PicoCalc, as root
|
||||
sh calculinux-console-font-6x12.sh
|
||||
sh /home/meshterm/MeshTerm/scripts/picocalc/calculinux-console-font-6x12.sh
|
||||
```
|
||||
|
||||
**Changing Wi-Fi.** Run `uwific` as root, as in [Step 7](#step-7--join-wi-fi). The boot-time
|
||||
kick picks up the new network on its own; it only needs `iwd` to know it.
|
||||
|
||||
**The six-minute boot without a dongle.** If the device is going to run permanently offline,
|
||||
the Wi-Fi kick is wasted time on every boot. Disable it:
|
||||
**The slow boot without a dongle.** If the device is going to run permanently offline,
|
||||
the Wi-Fi kick and the time sync are wasted time on every boot. Disabling the kick is not
|
||||
enough, because the time sync pulls it back in, so mask it. Then disable the time sync,
|
||||
which would otherwise still wait up to five minutes for a network:
|
||||
|
||||
```bash
|
||||
# on the PicoCalc, as root
|
||||
systemctl disable --now wifi-kick.service
|
||||
systemctl mask --now wifi-kick.service
|
||||
systemctl disable --now time-sync.service
|
||||
```
|
||||
|
||||
To undo it later, `systemctl unmask wifi-kick.service` and
|
||||
`systemctl enable time-sync.service`.
|
||||
|
||||
**The console font restores itself.** MeshTerm saves whatever font the console was using
|
||||
before it starts, and puts it back when it exits — on a normal quit and on a crash alike.
|
||||
You don't need to do anything to keep the shell's own font intact.
|
||||
@@ -876,10 +902,10 @@ You don't need to do anything to keep the shell's own font intact.
|
||||
|
||||
This whole path — from a stock PicoCalc kit through a running radio — has been exercised on
|
||||
one maintainer's bench: one Luckfox Lyra, one PicoCalc, one XIAO + Wio-SX1262 pair. It
|
||||
works. Some of it is also checked in code: a test parses the font script and pins it to
|
||||
MeshTerm's glyph inventory, the profile keys the scripts write are tested, the pinned
|
||||
MeshCore commit exists, the patch's two hunks are still needed on `dev`, and the nRF52840
|
||||
UF2 family id and both XIAO bootloader ids match Adafruit's board files.
|
||||
works. One part is also checked in code: a test (`tests/test_theme16.py`) parses the font
|
||||
script and pins it to MeshTerm's glyph inventory. The pinned MeshCore commit, the need for
|
||||
the patch's two hunks on `dev`, and the nRF52840 UF2 family id and XIAO bootloader ids
|
||||
against Adafruit's board files were checked by hand when this was written.
|
||||
|
||||
The rest is one bench's findings, and a second device may disagree:
|
||||
|
||||
|
||||
+12
-7
@@ -7,10 +7,13 @@ MeshTerm is drawn with emoji icons, braille charts and powerline path chips. Whe
|
||||
see them is up to your *terminal*, not really your font: a modern terminal, asked for a
|
||||
character its font doesn't have, quietly borrows it from another font on the machine.
|
||||
That's why the app looks right in Windows Terminal, in VS Code's terminal, and on macOS
|
||||
and Linux — usually with a font that contains almost none of it.
|
||||
and Linux — usually with a font that contains almost none of it. The exception is macOS's
|
||||
Terminal app, where the charts may draw misaligned: no Mac monospace font has braille, so
|
||||
it is borrowed from a proportional one at the wrong width.
|
||||
|
||||
The classic Windows console — the black `cmd.exe` window you get from a double-click —
|
||||
doesn't borrow. It draws what its one font holds and empty boxes for everything else, and
|
||||
The classic Windows console — the black `cmd.exe` window a double-click opens on
|
||||
Windows 10 — doesn't borrow. (Windows 11, 22H2 and later, opens Windows Terminal by
|
||||
default instead.) It draws what its one font holds and empty boxes for everything else, and
|
||||
no font fixes the icons there: the only two fonts on a Windows machine with emoji in them
|
||||
are proportional, and a console won't take a proportional font.
|
||||
|
||||
@@ -19,12 +22,14 @@ so, and opens there. Nothing is installed and nothing is changed; it's one windo
|
||||
of another, and it's the whole app exactly as the screenshots show it. Windows Terminal is
|
||||
already on every Windows 11 machine and is a free install on Windows 10.
|
||||
|
||||
Where there's no Windows Terminal to move to, MeshTerm offers the next best thing instead
|
||||
— the charts and marks, without the icons. It ships
|
||||
Where there's no Windows Terminal to move to, and the console's font can't already draw
|
||||
the charts, MeshTerm offers the next best thing instead — the charts and marks, without
|
||||
the icons. It ships
|
||||
[Cascadia Mono PL](https://github.com/microsoft/cascadia-code), Microsoft's own console
|
||||
font and one of the very few monospace faces that carries braille at all, and will install
|
||||
it just for you: no administrator rights, nothing downloaded. If you already have Cascadia
|
||||
it simply switches to it.
|
||||
it just for you: no administrator rights, nothing downloaded. If you already have a font
|
||||
that can draw the charts (Cascadia, or another such as Iosevka), it offers to switch to
|
||||
that one instead. Either way it asks first (`[y/N]`), and the answer defaults to no.
|
||||
|
||||
Preferences → Display → Console setup turns all of this off if you'd rather stay put.
|
||||
|
||||
|
||||
+68
-31
@@ -71,6 +71,8 @@ The bridge assumes the AIO's wiring by default:
|
||||
| Bandwidth | 62.5 kHz |
|
||||
| Coding rate | 4/5 |
|
||||
|
||||
The radio settings (frequency, spreading factor, bandwidth, coding rate) are MeshCore's
|
||||
US/Canada preset. Anywhere else, set the `MESHCORE_*` variables to your region's preset.
|
||||
Every one of these is overridable with a `MESHCORE_*` environment variable if your board or
|
||||
region differs — see [Hardware knobs](#hardware-knobs).
|
||||
|
||||
@@ -145,16 +147,18 @@ and `spi` and `gpio` in your `groups` output.
|
||||
|
||||
Which route you take depends on your Debian release:
|
||||
|
||||
- **trixie**, with `meshcore-uconsole` installed from the vendor's package: you already
|
||||
- **trixie**, with the `meshcore-uconsole` package (by cwill747) installed: you already
|
||||
have a working runtime (Python 3.13-based). Skip to [Step 3](#step-3--get-the-bridge).
|
||||
- **bookworm**: the `meshcore-uconsole` 1.12.0+ package is built for Python 3.13 and will
|
||||
**not run** — its virtualenv points at an interpreter bookworm doesn't have. Don't take
|
||||
the upgrade if apt offers it. Instead give the bridge a runtime of its own:
|
||||
- **bookworm**: the trixie `.deb` of `meshcore-uconsole` 1.12.0 is built on Python 3.13
|
||||
and needs glibc 2.38, so it will not install on bookworm, and the APT repository offers
|
||||
nothing for bookworm. Upstream's GitHub Releases also carry a separate bookworm `.deb`
|
||||
built on Python 3.11; it has not been tested with the bridge. The documented route is to
|
||||
give the bridge a runtime of its own:
|
||||
|
||||
```bash
|
||||
python3 -m venv ~/.local/share/meshterm-spi-bridge/venv
|
||||
~/.local/share/meshterm-spi-bridge/venv/bin/pip install "openhop-core[hardware]"
|
||||
```
|
||||
```bash
|
||||
python3 -m venv ~/.local/share/meshterm-spi-bridge/venv
|
||||
~/.local/share/meshterm-spi-bridge/venv/bin/pip install "openhop-core[hardware]"
|
||||
```
|
||||
|
||||
This is also the route to take if you'd rather not install the `meshcore-uconsole` package
|
||||
at all.
|
||||
@@ -215,8 +219,11 @@ If the first three checks all pass, you're ready to run it.
|
||||
./meshterm-spi-bridge --run
|
||||
```
|
||||
|
||||
This runs the preflight again, prints it, then starts the bridge in this terminal. A
|
||||
healthy startup logs something like:
|
||||
This runs the preflight again and prints it. Before it starts the bridge, it asks whether
|
||||
to add a `bridge` profile to your MeshTerm config
|
||||
(`` Add a 'bridge' profile to /home/you/.meshterm/config.toml so you can just run `meshterm`? [y/N] ``).
|
||||
Either answer is fine; Step 6 asks again if you say no. Then it starts the bridge in this
|
||||
terminal. A healthy startup logs something like:
|
||||
|
||||
```
|
||||
node runtime openhop_core 1.1.3 (/home/you/.local/share/meshterm-spi-bridge/venv/bin/python)
|
||||
@@ -230,7 +237,8 @@ READY — connect with: meshterm --tcp 127.0.0.1:5000
|
||||
The `radio config` line lists every setting as `key=value`, so the one above is
|
||||
shortened; yours is longer.
|
||||
|
||||
Leave it running, and in another terminal on the same machine try:
|
||||
Once MeshTerm is installed ([Step 7](#step-7--install-meshterm-and-connect)), you can test
|
||||
the bridge this way: leave it running, and in another terminal on the same machine run:
|
||||
|
||||
```bash
|
||||
meshterm --tcp 127.0.0.1:5000
|
||||
@@ -281,8 +289,9 @@ Menu option **4) Show status** prints the same information from inside the scrip
|
||||
Install MeshTerm on the uConsole. The simplest way is the Linux ARM64 one-file release:
|
||||
|
||||
```bash
|
||||
chmod +x meshterm-*-linux-arm64
|
||||
sudo mv meshterm-*-linux-arm64 /usr/local/bin/meshterm
|
||||
curl -fL -o meshterm https://github.com/jpmartineau/MeshTerm/releases/latest/download/meshterm-linux-arm64
|
||||
chmod +x meshterm
|
||||
sudo mv meshterm /usr/local/bin/meshterm
|
||||
```
|
||||
|
||||
Or install it from the repository with `pipx`:
|
||||
@@ -293,7 +302,8 @@ pipx install git+https://github.com/jpmartineau/MeshTerm
|
||||
pipx ensurepath
|
||||
```
|
||||
|
||||
If you accepted the profile in Step 6, your `config.toml` now has:
|
||||
If you accepted the profile in Step 5 or 6, `~/.meshterm/config.toml` now has this block
|
||||
(the bridge always writes to that path, even if you set `MESHTERM_HOME`):
|
||||
|
||||
```toml
|
||||
[profiles.bridge]
|
||||
@@ -314,13 +324,16 @@ or, without a profile:
|
||||
meshterm --tcp 127.0.0.1:5000
|
||||
```
|
||||
|
||||
You're connected when the device page or dashboard shows a node name (`uConsole` by
|
||||
You're connected when **Device info** or the dashboard shows a node name (`uConsole` by
|
||||
default) instead of a connection error. MeshTerm reports the device model as
|
||||
`pyMC-spi-bridge` — that's how you tell a bridged node from a real companion.
|
||||
|
||||
**Identity.** If the `meshcore-console` GUI's package is present, the bridge loads *that*
|
||||
package's identity key, so MeshTerm and the GUI are the same node — same contacts, same
|
||||
public key. On a library-only install, the bridge mints and keeps its own identity key
|
||||
package's identity key, so MeshTerm and the GUI share the same public key. Contacts and
|
||||
radio settings are the bridge's own: it keeps contacts in
|
||||
`~/.local/share/meshterm-spi-bridge/contacts.json`, and builds its radio settings from the
|
||||
`MESHCORE_*` variables and its defaults, never from the GUI's saved settings. Set the
|
||||
`MESHCORE_*` variables to match what the GUI uses. On a library-only install, the bridge mints and keeps its own identity key
|
||||
under `~/.local/share/meshterm-spi-bridge/identity.key`.
|
||||
|
||||
**Only one program may use the radio at a time.** Never run the bridge and the
|
||||
@@ -332,7 +345,15 @@ radio.
|
||||
## Updating and uninstalling
|
||||
|
||||
To update, pull or re-download `meshterm-spi-bridge` and reinstall the service (menu option
|
||||
2 again — it overwrites the copy in `~/.local/bin/`).
|
||||
2 again — it overwrites the copy in `~/.local/bin/`). The running service keeps the old
|
||||
code until you restart it:
|
||||
|
||||
```bash
|
||||
systemctl --user restart meshterm-spi-bridge.service
|
||||
```
|
||||
|
||||
Option 2 also rewrites the unit file, so any `Environment=` lines you added to it by hand
|
||||
are lost. Put them in a drop-in instead, as [Hardware knobs](#hardware-knobs) shows.
|
||||
|
||||
To remove the bridge, run the menu and choose **3) Uninstall the service**. This stops and
|
||||
removes the `systemd --user` unit and the installed script copy. It does **not** touch
|
||||
@@ -344,16 +365,31 @@ that block by hand if you no longer want it.
|
||||
|
||||
## Hardware knobs
|
||||
|
||||
The defaults match the hackergadgets uConsole AIO, so a stock AIO needs none of these. They
|
||||
exist for a revision or a board that differs: export what differs before launching the
|
||||
bridge, or put the lines in the service's environment.
|
||||
The pin defaults match the hackergadgets uConsole AIO v1, which needs none of these. The
|
||||
**AIO v2 needs `MESHCORE_EN_PINS=27`**, whether or not the `meshcore-console` package is
|
||||
installed. The radio settings default to the US/Canada preset. For a foreground run, export
|
||||
what differs before launching the bridge. For the service, add a drop-in, which survives a
|
||||
reinstall:
|
||||
|
||||
```bash
|
||||
systemctl --user edit meshterm-spi-bridge.service
|
||||
```
|
||||
|
||||
and put the variables under a `[Service]` heading, one `Environment=` line each:
|
||||
|
||||
```ini
|
||||
[Service]
|
||||
Environment=MESHCORE_EN_PINS=27
|
||||
```
|
||||
|
||||
Then `systemctl --user restart meshterm-spi-bridge.service`.
|
||||
|
||||
| Variable | What it sets |
|
||||
| --- | --- |
|
||||
| `MESHCORE_BUS_ID`, `MESHCORE_CS_ID`, `MESHCORE_CS_PIN` | which SPI bus, device and chip-select pin the radio is on |
|
||||
| `MESHCORE_RESET_PIN`, `MESHCORE_BUSY_PIN`, `MESHCORE_IRQ_PIN` | the three control lines |
|
||||
| `MESHCORE_FREQUENCY`, `MESHCORE_TX_POWER` | frequency in Hz, power in dBm |
|
||||
| `MESHCORE_SPREADING_FACTOR`, `MESHCORE_BANDWIDTH`, `MESHCORE_CODING_RATE` | the modem preset — all three must match the mesh you are joining |
|
||||
| `MESHCORE_SPREADING_FACTOR`, `MESHCORE_BANDWIDTH`, `MESHCORE_CODING_RATE` | the modem preset — all three must match the mesh you are joining. Whole numbers only: bandwidth in Hz (`62500`), coding rate as the denominator (`5` for 4/5). A decimal or `4/5` stops the bridge at startup. |
|
||||
| `MESHCORE_TXEN_PIN`, `MESHCORE_RXEN_PIN`, `MESHCORE_EN_PINS` | the RF-switch and power-enable lines a board may need (`-1` for none; `EN_PINS` is a comma list — the AIO v2 wants `27`) |
|
||||
| `MESHCORE_USE_DIO2_RF`, `MESHCORE_USE_DIO3_TCXO`, `MESHCORE_IS_WAVESHARE` | whether DIO2 drives the RF switch and DIO3 the TCXO (both on for the AIO), and a flag for a different vendor's wiring the runtime knows about |
|
||||
| `MESHCORE_GPIO_CHIP`, `MESHCORE_USE_GPIOD_BACKEND`, `MESHCORE_PREAMBLE_LENGTH` | which gpiochip, whether to drive it through `gpiod`, and the LoRa preamble |
|
||||
@@ -361,10 +397,11 @@ bridge, or put the lines in the service's environment.
|
||||
|
||||
The bridge passes a knob only when the runtime's radio constructor accepts it, so the same
|
||||
environment works under `pymc_core` 1.0.x, which lacks the newer ones. Where the
|
||||
`meshcore-console` package is installed, the bridge builds the radio through *its* hardware
|
||||
configuration, which reads the same names plus a few more of its own — see that package's
|
||||
documentation. On a library-only install the table above is the whole of it, so an AIO v2
|
||||
without that package present may not power its radio.
|
||||
`meshcore-console` package is installed, the bridge builds the radio through that
|
||||
package's environment reader, which reads the same names plus a few more of its own (see
|
||||
that package's documentation) and ignores the GUI's saved presets. On a library-only
|
||||
install the table above is the whole of it. Either way, an AIO v2 without
|
||||
`MESHCORE_EN_PINS=27` will not power its radio.
|
||||
|
||||
---
|
||||
|
||||
@@ -375,10 +412,10 @@ without that package present may not power its radio.
|
||||
| `node runtime` fails in the preflight | Did you build the venv in [Step 2](#step-2--install-the-radio-runtime)? Is `MESHTERM_PYMC_PYTHON` pointing at the right interpreter, if set? |
|
||||
| `SPI device` shows "no /dev/spidev* found" | Is `dtoverlay=spi1-1cs` in `/boot/firmware/config.txt`? Did you reboot after adding it? |
|
||||
| `SPI device` or `GPIO chip` shows a permission error | Are you in the `spi` and `gpio` groups (`groups`)? Did you log out and back in after `usermod`? |
|
||||
| Preflight warns "radio in use — meshcore-console is running" | Close the GUI before running or installing the bridge. |
|
||||
| Preflight warns "port 5000 busy" | Something else is already listening there — check `systemctl --user status meshterm-spi-bridge.service` for an already-running instance. |
|
||||
| Bridge starts but `radio.begin()` fails after 4 attempts | GPIO lines may still be held by a session that just closed — wait a few seconds and try again. |
|
||||
| MeshTerm connects but direct messages to an old contact say "not found" | Restart the bridge — contacts are restored from its snapshot file at startup; if the snapshot is missing, the contact needs to be heard again. |
|
||||
| Preflight warns `radio in use meshcore-console is running:` | Close the GUI before running or installing the bridge. |
|
||||
| Preflight warns `port 5000 busy something is already on 127.0.0.1:5000` | Something other than the bridge service is listening there (an active service is reported as `bridge service running` instead). Usually it is a foreground `--run` in another terminal; stop that one. |
|
||||
| Bridge exits with `bridge failed: GPIO pins still busy after retries` | The bridge retries `radio.begin()` four times only when the GPIO lines are busy. They may still be held by a session that just closed — wait a few seconds and try again. |
|
||||
| MeshTerm connects but direct messages to an old contact say "not found" | Contacts are restored from the bridge's snapshot file at startup. If the contact is not in it, wait until the contact is heard again. |
|
||||
| Reboot, factory reset, or setting a device PIN silently does nothing | Expected — the radio library has no handler for these three, whatever runtime you're on. |
|
||||
| Traces or the live feed don't show up | These rely on compatibility shims the bridge installs (or, under `openhop_core`, on the library's own equivalents). Check the bridge's log for lines starting `compat:` to confirm they're wired. |
|
||||
|
||||
@@ -390,7 +427,7 @@ This has been verified on a bookworm uConsole with `openhop-core` 1.1.3: the rad
|
||||
contacts are restored across a restart, and `info` and `contacts` answer correctly over the
|
||||
TCP connection. The older `pymc-core` 1.0.x path, with all three of the bridge's
|
||||
compatibility shims active, has been exercised in full, including traces and the live feed.
|
||||
Every interface the bridge calls in both runtimes is checked by MeshTerm's test suite.
|
||||
MeshTerm's test suite does not cover the bridge.
|
||||
|
||||
What has not been confirmed:
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ Repo-side tools. None of these ship in the wheel.
|
||||
| Script | What it is for |
|
||||
|---|---|
|
||||
| `basemap-doctor.py` | Why a user's map has no basemap — certificates, DNS, proxy, or colour depth |
|
||||
| `picocalc/` | Calculinux device setup: console font, palette, Wi-Fi, radio bridge |
|
||||
| `picocalc/` | Calculinux device setup: console font, palette, Wi-Fi; `xiao-radio/` is the XIAO radio kit (firmware build, flashing, UART setup) |
|
||||
| `uconsole/` | The uConsole SPI bridge service |
|
||||
|
||||
## basemap-doctor.py
|
||||
|
||||
@@ -4,7 +4,7 @@ A Seeed XIAO nRF52840 + Wio-SX1262 wired to the Luckfox Lyra's UART1, running Me
|
||||
companion firmware on `Serial1`, so MeshTerm on the PicoCalc opens `/dev/ttyS1` like any
|
||||
other serial companion. No BLE, no USB host, no SD-slot sacrifice.
|
||||
|
||||
**The step-by-step guide is [`docs/picocalc.md`](../../../docs/picocalc.md), Phase 3** — parts,
|
||||
**The step-by-step guide is [`docs/picocalc.md`, Phase 3](../../../docs/picocalc.md#phase-3--add-the-radio)** — parts,
|
||||
the firmware build and the patch explained, flashing, wiring, the Lyra setup, and what has
|
||||
only been proven on one bench. What the register poke does is in `uart1-mux.py`'s own
|
||||
header. This page is the bench card.
|
||||
|
||||
Reference in new issue
Block a user