The changelog is in ASD-STE100

Each version, date, fact, and link stays. The version headings use the
Keep a Changelog form (## [x.y.z] - date); the release workflow reads only
the bracketed version, and each section still extracts.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jean-Pierre MartineauandClaude Opus 5.5 committed 2026-10-06 21:44:55 -04:00
1 parent 26d422e651
commit bc51115d24
1 file changed
+234 -202
+234 -202
View File
@@ -1,257 +1,289 @@
# Changelog
Notable changes to MeshTerm, newest first.
This page lists the notable changes to MeshTerm. The newest version is first.
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the
version numbers follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html) — with
one caveat SemVer makes for a leading zero: while the major version is still `0`, a
**minor** bump is allowed to change how things behave, not just add to them.
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). The
version numbers follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html). One
rule of SemVer applies to a leading zero: while the major version is `0`, a **minor** bump
can change how things behave. It does not only add new things.
## [Unreleased]
## [0.10.2] — 2026-09-29
## [0.10.2] - 2026-09-29
**Harder to leave by accident, a scope picker on the dashboard and the Time Machine, and
T-Deck Bluetooth pairing.** Esc no longer walks you into the quit dialog, ^Q asks before it
quits, both traffic screens can narrow to one region, and a T-Deck on MeshOS or wadamesh
pairs like any other companion.
**It is harder to leave the app by accident. The dashboard and the Time Machine have a scope
picker. A T-Deck can pair over Bluetooth.** Esc no longer takes you to the quit dialog. ^Q
asks before it quits. Both traffic screens can show one region only. A T-Deck that runs
MeshOS or wadamesh pairs like any other companion.
### Added
- **The dashboard and the Time Machine can show one scope at a time.** Press `s` (F3 on the
dashboard, F2 on the Time Machine, on the PicoCalc) to step through all traffic, unscoped
floods, each region heard, and floods of an unknown scope. The charts, counts, and signal
figures narrow to that scope, and the title says which one you are looking at. A direct
packet has no scope, so it only counts under all.
- The Channels list leads with each channel's slot number.
- The Contacts title counts archived contacts too, and shortens itself on a narrow screen.
- **The dashboard and the Time Machine can show one scope at a time.** Press `s` to step
through these views: all traffic, unscoped floods, each region heard, and floods of an
unknown scope. On the PicoCalc, press F3 on the dashboard or F2 on the Time Machine. The
charts, the counts, and the signal figures show only that scope. The title says which
scope you look at. A direct packet has no scope, so it counts only under all traffic.
- The Channels list now starts each row with the slot number of the channel.
- The Contacts title now counts archived contacts too. On a narrow screen, the title
becomes shorter.
### Changed
- **Esc at the main menu no longer opens the quit dialog.** Pressing Esc again and again is
the natural way back to the menu, and the presses that landed after you got there used to
ask whether you wanted to quit. Now Esc stops at the menu (it still clears a typed
filter), and you leave through the Quit row or ^Q.
- **^Q asks before it quits, from any screen.** It sits right next to ^W, which goes back to
the menu, so one slip used to close the app, along with any capture or queued message.
Now it opens the same dialog as the Quit row, whatever you were doing keeps running
behind it, and Esc puts you back. Pressing ^Q a second time quits straight away. The main
menu names it: `^Q quit?` on the hint line, or, on the PicoCalc, in the title bar, with
**Quit?** on F3 and **Quit!** (no question) on Shift+F3.
- **The dashboard counts each packet once.** Its traffic list used to count an advert twice,
once as the device reported it and once as the frame it arrived in. It now counts frames
heard on the air, under the same names and colours as the live feed.
- The splash screen has new art, and its white letters no longer come out grey.
- The Support page's Patreon link is shorter, and so is its QR code.
- **Esc at the main menu no longer opens the quit dialog.** Many users press Esc again and
again to go back to the menu. The presses that came after they arrived used to ask if
they wanted to quit. Now Esc stops at the menu. It still clears a typed filter. To leave
the app, use the Quit row or ^Q.
- **^Q asks before it quits, from any screen.** The ^Q key is next to ^W, which goes back to
the menu. Before, one wrong key press closed the app, and a capture or a queued message
was lost. Now ^Q opens the same dialog as the Quit row. Your work continues behind the
dialog, and Esc takes you back. A second ^Q quits at once. The main menu shows this
key. The hint line says `^Q quit?`. On the PicoCalc, the title bar says it, F3 is
**Quit?**, and Shift+F3 is **Quit!** (it quits with no question).
- **The dashboard counts each packet one time.** Before, its traffic list counted an advert
two times: one time as the device reported it, and one time as the packet that carried it.
Now it counts the packets that MeshTerm hears on the air. It uses the same names and
colours as the live feed.
- The splash screen has new art, and its white letters are no longer grey.
- The Patreon link on the Support page is shorter, and its QR code is shorter too.
### Fixed
- **A T-Deck running MeshOS or wadamesh pairs over Bluetooth.** Those firmwares refuse the
first message until the device is paired, and MeshTerm read the silence as "this isn't a
MeshCore companion", so the PIN prompt never came. It now recognises the refusal and
pairs the way it does with any other companion. On Windows, a mistyped PIN also no longer
leaves behind a half-made pairing that made the next, correct attempt fail.
- **Rebooting from Device config shows the reconnect dialog straight away.** A board behind
a USB serial adapter could restart without MeshTerm noticing, and it kept sending
commands to a board that was mid-restart. Over Bluetooth, the reboot also no longer waits
a second or more for a reply the restarting board never sends.
- **A T-Deck that runs MeshOS or wadamesh pairs over Bluetooth.** These firmwares refuse the
first message until the device is paired. MeshTerm took the silence to mean that this is
not a MeshCore companion, so the PIN prompt did not come. Now MeshTerm knows this refusal
and pairs the same way as with any other companion. On Windows, a wrong PIN no longer
leaves a half-made pairing. Before, that pairing made the next correct try fail.
- **When you reboot from Device config, the reconnect dialog shows at once.** A board behind
a USB serial adapter could restart without MeshTerm knowing. MeshTerm then sent commands
to a board that was in the middle of a restart. Over Bluetooth, the reboot also no longer
waits for one second or more for a reply that the restarting board never sends.
## [0.10.1] — 2026-09-27
## [0.10.1] - 2026-09-27
**Three small fixes to the command line.** A mistyped `records --width` now says so instead
of looking like an empty result, the simulator's row in `devices` loses a stray `()`, and
two help pages read like the rest.
**Three small fixes to the command line.** A wrong `records --width` now gives an error
instead of an empty result. The row of the simulator in `devices` no longer shows a stray
`()`. Two help pages now read like the other help pages.
### Fixed
- **`meshterm records --width` refuses a width that doesn't exist.** Hash widths are 1, 2,
or 4. Any other number used to look like an empty result, so a typo and an empty
database gave the same answer, and `--width 0` was ignored and listed every width. Now
it's a usage error that names the three choices, like `--category` already was.
- **The simulator's row in `meshterm --mock devices` no longer ends in an empty `()`.**
The brackets hold a serial port, and the simulator doesn't have one.
- **`meshterm platform --help` and `meshterm specimen --help` read like the others.** They
used to print notes meant for someone reading the source code, markup and all, and cut
their summaries short in `meshterm --help`. Now each has one plain line.
- **`meshterm records --width` refuses a width that does not exist.** The hash widths are 1,
2, or 4. Before, any other number gave what looked like an empty result. A typo and an empty
database gave the same answer. Also, `--width 0` had no effect and listed every width. Now
a wrong width is a usage error that names the three choices, like `--category`.
- **The row of the simulator in `meshterm --mock devices` no longer ends in an empty `()`.**
The brackets hold a serial port, and the simulator has no serial port.
- **`meshterm platform --help` and `meshterm specimen --help` read like the other help
pages.** Before, they printed notes for a person who reads the source code, with the
markup. They also cut their summaries short in `meshterm --help`. Now each command has one
plain line.
## [0.10.0] — 2026-09-25
## [0.10.0] - 2026-09-25
**Regions, a uConsole with no bridge, and Bluetooth that works on Linux.** MeshTerm now
speaks MeshCore's regions: it reads and edits them on a repeater, keeps a channel's messages
inside one, and tells you which region any flood it hears was sent into. It drives the
uConsole's LoRa radio itself. And connecting is far less of a mystery: a PIN-protected
companion pairs on Linux, and a connection that fails says which step failed and what to do.
speaks the regions of MeshCore. It reads and edits the regions of a repeater. It keeps the
messages of a channel inside one region. It also tells you which region each heard flood
was sent into. MeshTerm drives the LoRa radio of the uConsole itself. A connection is also
much easier to understand. A companion with a PIN pairs on Linux. When a connection fails,
MeshTerm says which step failed and what to do.
### Added
- **MeshTerm drives the uConsole's LoRa radio itself, without the bridge service.** A radio
on this machine's own SPI bus is now a connection like USB, Bluetooth, or TCP: pick
**SPI radio** on the device screen, or run `meshterm --spi`, and `meshterm devices` lists
it beside everything else. MeshTerm starts the node when it connects and stops it when it
quits, so the radio is free for other programs whenever MeshTerm is closed — even after a
crash. The node keeps its identity, name, radio settings, channels, and contacts in
`~/.meshterm/radio/`, and the first time it runs it takes over the bridge's identity and
contacts, so it stays the node everyone already knows. It needs the radio library
(`pipx inject mesh-term 'openhop-core[hardware]'`), and a board wired differently from
the AIO v1 states its pins in a profile's `spi` table. The bridge is still there for a
node that should stay on the mesh while MeshTerm is closed.
- **MeshTerm drives the LoRa radio of the uConsole itself, with no bridge service.** A
radio on the SPI bus of this machine is now a connection, like USB, Bluetooth, or TCP.
To use it, select **SPI radio** on the device screen, or run `meshterm --spi`. The
command `meshterm devices` lists it with the other connections. MeshTerm starts the node
when it connects and stops the node when it quits. Thus the radio is free for other
programs each time MeshTerm is closed, also after a crash. The node keeps its identity,
name, radio settings, channels, and contacts in `~/.meshterm/radio/`. The first time that
the node runs, it takes the identity and the contacts of the bridge. Thus it stays the
node that everyone already knows. It needs the radio library
(`pipx inject mesh-term 'openhop-core[hardware]'`). A board that has different wiring than
the AIO v1 gives its pins in the `spi` table of a profile. The bridge is still there for a
node that must stay on the mesh while MeshTerm is closed.
([#21](https://github.com/jpmartineau/MeshTerm/issues/21))
- **A repeater's regions, read and edited.** A repeater's node page shows the regions it
relays floods for, and whether it relays unscoped floods too; **Ask which regions it
carries** asks it once (a repeater answers only a neighbour, or over a known route).
Repeater admin gains a **Regions** page for the whole tree: allow or deny floods per region
and for unscoped traffic, set the home and default scope, add and remove regions, and save.
Every edit takes effect at once on the repeater, and a reboot undoes whatever was not
saved, so the page counts your unsaved edits and asks before you leave with any. A tree
too big for one reply is said to be cut, and the rest is recovered from the repeater's own
lists. On the command line, `meshterm regions NODE` asks the same question.
- **A channel can be kept to one region.** Give a channel a **Send scope** on its page, and
its messages are flooded into that region alone — only repeaters that carry it relay them.
The chat's title names the scope, and **^R** resends the message you picked (or your last
one) unscoped when the region is getting it nowhere. A radio that can't send under the
scope refuses before anything goes out, rather than quietly sending it everywhere. On the
command line, `channels scope INDEX [REGION]` reads or sets it, `channels list` gains a
`SCOPE` column, and `chat send --channel N --scope REGION` (or `--scope '*'` for unscoped)
overrides it for one message. Scoped sending needs firmware 1.10, and `*` needs 1.16.
- **Every flood says which region it was sent into.** The packet viewer has a `scope` row,
the live feed a `SCOPE` lane, and a received channel message's card names its region too.
Where no region known here matches, the code is shown instead, and it turns into a name
as soon as a repeater or a channel teaches it one. `monitor` gains the same `SCOPE` column
and a `scope` field under `--json`. Packets recorded before this version have no scope.
- **A message you sent says what it was sent under.** Its message paths dialog names the
scope, and when nothing relayed it and no repeater known here carries that region, it
says so — which is usually the answer to "why did nobody hear that?"
- **You can read and edit the regions of a repeater.** The node page of a repeater shows the
regions for which it relays floods. It also shows if it relays unscoped floods. Select
**Ask which regions it carries** to ask it one time. A repeater answers only a neighbour,
or a request over a known route. Repeater admin has a new **Regions** page for the whole
tree. On this page, you can do these tasks:
- Allow or deny floods for each region, and for unscoped traffic.
- Set the home scope and the default scope.
- Add and remove regions.
- Save the changes.
Each edit takes effect on the repeater at once. A reboot cancels the edits that you did
not save. Thus the page counts your unsaved edits, and it asks before you leave with
unsaved edits. Sometimes the tree is too big for one reply. Then the page says that the
tree is cut, and it gets the rest from the lists of the repeater. On the command line,
`meshterm regions NODE` asks the same question.
- **You can keep a channel to one region.** Give a channel a **Send scope** on its page.
MeshTerm then floods its messages into that region only, and only the repeaters that carry
the region relay them. The title of the chat names the scope. Press **^R** to send again
the message that you selected (or your last message) as unscoped. Use this when the region
does not deliver the message. If the radio cannot send under the scope, it refuses before
it sends anything. Before, the message could go out everywhere with no warning. On the
command line, `channels scope INDEX [REGION]` reads or sets the scope. `channels list` has
a new `SCOPE` column. For one message, `chat send --channel N --scope REGION` changes the
scope. Use `--scope '*'` to send it unscoped. Scoped sending needs firmware 1.10, and `*`
needs firmware 1.16.
- **Each flood now shows the region that it was sent into.** The packet viewer has a `scope`
row, and the live feed has a `SCOPE` lane. The card of a received channel message also
names its region. If no region that MeshTerm knows matches, it shows the code. The code
changes to a name when a repeater or a channel gives MeshTerm that name. `monitor` has the
same `SCOPE` column, and a `scope` field under `--json`. A packet that MeshTerm stored
before this version has no scope.
- **A message that you sent shows the scope that it used.** Its message paths dialog names
the scope. If no repeater relayed the message, and no repeater that MeshTerm knows carries
that region, the dialog says this. This is often the answer to the question "why did nobody
hear that?"
### Changed
- **MeshTerm sends at most one automatic advert a week, and none unless you ask.** A
MeshCore companion never advertises by itself, so the hourly zero-hop and daily flood
adverts MeshTerm sent by default were the only automatic adverts on the air — more than
a companion needs, on a shared channel. They are gone from Device config, along with
`config advert-cadence`. In their place is one preference, **Weekly advert**, off by
default: once a device has gone a week without a flood advert, MeshTerm floods one, after
it has heard the mesh and then waited for **Advert quiet** seconds of silence (5, 15, 30,
or 60; 30 by default) plus a random 0–5 s, so two waiting radios do not collide. A line
under the setting says where the week stands. Switching it on starts the week rather than
sending; a flood advert sent by hand restarts it; each device keeps its own week, and one
that falls due while MeshTerm is closed goes out the next time that device connects. The
two old cadence preferences are dropped from `preferences.toml` the next time it is saved.
- The live feed's packet classes take shorter names in a narrower column that never cuts
them off, and the SNR and RSSI labels line up with their lanes. On the PicoCalc the class
drops its icon to make room.
- The Channels list reads **LAST** before **MSGS**, and shows a **SCOPE** column only when a
channel has one.
- **MeshTerm sends one automatic advert each week at most, and none unless you ask.** A
MeshCore companion never sends an advert by itself. Thus the hourly zero-hop advert and
the daily flood advert, which MeshTerm sent by default, were the only automatic adverts on
the air. A companion does not need so many, and they used a shared channel. They are now
removed from Device config, with `config advert-cadence`. A new preference replaces them:
**Weekly advert**. It is off by default. When it is on, MeshTerm floods one advert after a
device has gone one week with no flood advert. MeshTerm first hears the mesh. Then it
waits for **Advert quiet** seconds of silence (5, 15, 30, or 60, with 30 as the default),
and for a random time of 0 to 5 s more. The random time stops two waiting radios from
colliding. A line under the setting shows where the week stands. When you switch the
preference on, it starts the week. It does not send an advert. A flood advert that you
send by hand starts the week again. Each device has its own week. If the week ends while
MeshTerm is closed, the advert goes out the next time that the device connects. MeshTerm
removes the two old cadence preferences from `preferences.toml` the next time that it
saves the file.
- The packet classes of the live feed have shorter names, in a narrower column that never
cuts them off. The SNR and RSSI labels now line up with their lanes. On the PicoCalc, the
class has no icon, to make room.
- The Channels list now shows **LAST** before **MSGS**. It shows a **SCOPE** column only when
a channel has a scope.
### Fixed
- **Bluetooth on Linux works with a PIN-protected companion.** The PIN never reached the
radio: pairing fell back to a no-PIN ceremony the firmware refuses, so a correct PIN was
reported as rejected, again and again. MeshTerm now runs the pairing itself and answers
with the PIN, so it works over SSH and on machines with no desktop, and a companion that
was paired before it had a PIN is paired again properly. An unpaired companion with no PIN
given is now reported in seconds rather than after 30. **Unpair & quit** works on Linux
too.
- **A Bluetooth connect on Linux no longer loses its own link.** When the radio needed a few
tries to open a link — routine on a Raspberry Pi — MeshTerm lost track of the one that
finally opened. The companion, still connected, stopped advertising, so the retry could
not find it and MeshTerm reported it out of range.
- **A connection that fails says which step failed.** Bluetooth now tells a link that never
opened from a stale saved pairing, a wrong PIN, a companion that refused to pair, and a
connect that timed out, and the PIN dialog shows the reason instead of calling every
refusal a wrong PIN. A USB port says whether it is missing, in use by another program
(ModemManager, on Linux), or not yours to open (the `dialout` group). Every message, and
what to do about it, is in
[When a companion won't connect](https://github.com/jpmartineau/MeshTerm/blob/main/docs/guide/connecting.md).
- **Clock sync explains a radio whose clock is ahead, instead of calling it malformed.**
MeshCore firmware never sets its clock back, so once a radio's clock ran ahead of the
computer's — a GPS fix, another app, drift — every sync was refused and logged as "the
device rejected the request as malformed". MeshTerm now reads the radio's clock first: a
few seconds ahead counts as in sync, and further ahead says by how much and that rebooting
the radio resets it.
- **The Channels page no longer loses channels at connect.** When the radio refused another
command while MeshTerm was reading its channel slots, the refusal was taken for "no such
slot", and every channel after it was missing for the rest of the session.
- **The uConsole's radio hears the whole mesh.** Its SPI node, and the bridge, listened for a
shorter preamble than MeshCore sends, so the chip gave up on most packets part-way through
and decoded one only when it happened to catch the end. It now expects the preamble the
mesh uses for the spreading factor in force.
- **The default flood scope is stored the way the firmware and the MeshCore app store it.**
MeshTerm saved it as `#name` where they save `name`, refused a 30-character name the
firmware accepts, and mis-framed a name with an accent. Device config now also refuses a
name no repeater could list back (spaces, commas, or a private `$` region).
- **The SPI bridge remembers its channels across restarts.** It kept them only in memory, so
after every reboot the Channels page came up empty. For this fix and the preamble one,
run the bridge's setup menu again and choose **2) Install as a service**.
- **Bluetooth on Linux works with a companion that has a PIN.** Before, the PIN did not
reach the radio. The pairing changed to a ceremony with no PIN, which the firmware
refuses. Thus a correct PIN was reported as wrong, again and again. Now MeshTerm does the
pairing itself and answers with the PIN. It works over SSH, and on machines with no
desktop. A companion that was paired before it had a PIN is now paired again correctly.
When a companion is not paired and you gave no PIN, MeshTerm now reports this in seconds.
Before, it took 30 seconds. **Unpair & quit** also works on Linux.
- **A Bluetooth connection on Linux no longer loses its own link.** Sometimes the radio
needs a few tries to open a link. This is normal on a Raspberry Pi. Before, MeshTerm lost
the link that finally opened. The companion was still connected, so it stopped sending
advertisements. The next try could not find it, and MeshTerm reported that it was out of
range.
- **A connection that fails says which step failed.** Bluetooth now shows the difference
between these cases:
- A link that never opened.
- A saved pairing that is no longer good.
- A wrong PIN.
- A companion that refused to pair.
- A connection that timed out.
## [0.9.0] — 2026-09-22
The PIN dialog shows the reason. Before, it called each refusal a wrong PIN. A USB port
now says if it is missing, if another program uses it (ModemManager, on Linux), or if you
do not have the right to open it (the `dialout` group). Each message, and what to do about
it, is in
[When a companion does not connect](https://github.com/jpmartineau/MeshTerm/blob/main/docs/guide/connecting.md).
- **Clock sync explains a radio that has a clock that is ahead.** Before, it called this
"malformed". MeshCore firmware never sets its clock back. Thus, when the clock of a radio
was ahead of the clock of the computer (because of a GPS fix, another app, or drift),
the radio refused each sync. MeshTerm logged this as "the device rejected the request as
malformed". Now MeshTerm reads the clock of the radio first. If the radio is a few seconds
ahead, MeshTerm counts it as in sync. If the radio is more ahead, MeshTerm says by how
much, and that a reboot of the radio resets the clock.
- **The Channels page no longer loses channels when it connects.** Sometimes the radio
refused one more command while MeshTerm read the channel slots. MeshTerm took the refusal
to mean "no such slot". Thus each channel after that slot was missing for the rest of the
session.
- **The radio of the uConsole hears the whole mesh.** Its SPI node, and the bridge, listened
for a preamble that was shorter than the preamble that MeshCore sends. Thus the chip gave
up on most packets before the end. It decoded a packet only when it caught the end by
chance. Now it expects the preamble that the mesh uses for the spreading factor that is in
use.
- **MeshTerm stores the default flood scope in the same way as the firmware and the MeshCore
app.** Before, it stored `#name` where they store `name`. It refused a name of 30
characters, which the firmware accepts. It also built a wrong protocol frame for a name
with an accent. Device config now also refuses a name that no repeater can list back. These names
have spaces, commas, or a private `$` region.
- **The SPI bridge remembers its channels when it restarts.** Before, it kept the channels
only in memory. Thus the Channels page was empty after each reboot. For this fix and the
preamble fix, run the setup menu of the bridge again and select **2) Install as a
service**.
**The first public release.** Everything in MeshTerm is new today, so instead of a list of
changes, here is what it does.
## [0.9.0] - 2026-09-22
MeshTerm is a program you run in a terminal to work with a **MeshCore** radio — one of the
small LoRa boards people use to build long-range mesh networks. A mesh like that needs no
internet, no phone signal, and nobody in the middle: the radios pass messages along to each
other until they arrive. You plug one into your computer, start MeshTerm, and it shows you
what the mesh is doing.
**The first public release.** Everything in MeshTerm is new today. Thus this entry does not
list changes. It says what MeshTerm does.
MeshTerm is a program that you run in a terminal to work with a **MeshCore** radio. This is
one of the small LoRa boards that people use to build long-range mesh networks. Such a mesh
needs no internet, no phone signal, and no node in the middle. The radios pass the messages
from one to the next until they arrive. Connect one radio to your computer and start
MeshTerm. It shows you what the mesh does.
### What you can do with it
- **Run it two ways, and it behaves the same either way.** Type `meshterm` on its own and
you get a full-screen menu you drive with the arrow keys. Type a command instead —
`meshterm contacts`, `meshterm info` — and it prints an answer and exits, which is what you
want in a script. Add `--json` to nearly any command and the answer comes back as data
for another program to read.
- **Run it in two ways. It behaves the same in both ways.** Type `meshterm` alone to get a
full-screen menu that you use with the arrow keys. Or type a command, for example
`meshterm contacts` or `meshterm info`. MeshTerm prints an answer and exits. This is good
for a script. Add `--json` to nearly all commands, and the answer comes as data that
another program can read.
- **It listens all the time, and writes down what it hears.** Radios on a mesh announce
themselves. From the moment yours is connected, MeshTerm notes down every announcement it
overhears: which radio it was, how strong the signal was, and where it said it was. All of
it is saved on your own computer. That is why the lists and charts can show you not only
what is happening now, but what was happening last Tuesday.
- **It listens all the time, and it stores what it hears.** The radios on a mesh announce
themselves. When your radio is connected, MeshTerm notes each announcement that it hears.
It notes which radio sent it, how strong the signal was, and where the radio said that it
was. MeshTerm stores all of this on your own computer. Thus the lists and the charts can
show what happens now, and also what happened last Tuesday.
- **You can see where everyone is.** There is a street map, drawn in the terminal, with the
radios on it. You can pan it, zoom it, and search it. There is also a Time Machine: charts of
everything you have ever overheard, so you can see when a radio usually talks and how
well you have heard it, over a day, a week, a month, or all of it.
- **You can see where everyone is.** MeshTerm draws a street map in the terminal, with the
radios on it. You can pan the map, zoom it, and search it. There is also a Time Machine.
It has charts of everything that you ever heard. You can see when a radio usually talks,
and how well you heard it. You can see one day, one week, one month, or all of the time.
- **You can talk to people.** Group channels and one-to-one messages, both live. If someone
is out of range right now, the courier holds your message and delivers it when they come
back. Channels can be shared as a QR code someone else scans, or as a link.
- **You can talk to people.** MeshTerm has group channels and one-to-one messages, and both
are live. If a person is out of range now, the courier holds your message. It delivers the
message when the person comes back. You can share a channel as a QR code that another
person scans, or as a link.
- **You can measure the mesh, not just guess at it.** Trace a message's route and see which
hop is the weak one. Sweep your transmit power from coarse to fine to find the lowest
setting that still gets through. Walk a map of how the whole mesh actually hangs together,
which is often not how you thought it did.
- **You can measure the mesh. You do not need to guess.** Trace the route of a message, and
see which hop is the weak one. Sweep your transmit power from coarse to fine, to find the
lowest setting that still gets through. Walk a map of how the whole mesh is really
connected. Often, it is not connected in the way that you thought.
- **It talks to your radio however your radio talks.** USB cable, Bluetooth, or over the
network. It finds the ones it can find on its own and asks you to pick. If a connection
drops it reconnects by itself. No radio yet? `meshterm --mock` runs the whole program
against a simulated mesh, and records what it hears in a history database of its own,
apart from your real one.
- **It talks to your radio in the way that your radio talks.** MeshTerm uses a USB cable,
Bluetooth, or the network. It finds the radios that it can find by itself, and asks you to
select one. If a connection drops, MeshTerm connects again by itself. If you have no
radio yet, `meshterm --mock` runs the whole program against a simulated mesh. It stores
what it hears in a history database of its own, apart from your real database.
- **It runs on the small machines too.** The PicoCalc gets a layout of its own, built
for its 53-column screen, with its own fonts, colours and on-screen key labels. The
uConsole has room for the full desktop layout, and runs that.
- **It runs on the small machines too.** The PicoCalc has a layout of its own, for its
screen of 53 columns. It also has its own fonts, colours, and on-screen key labels. The
uConsole has room for the full desktop layout, and it runs that layout.
- **It works with no internet.** Map tiles are kept on disk once fetched, and when there is
no network at all the map falls back to a plain grid. Nothing about MeshTerm needs to
phone home.
- **It works with no internet.** MeshTerm keeps the map tiles on disk after it downloads
them. When there is no network at all, the map changes to a plain grid. MeshTerm never
needs to contact a server to work.
- **When something goes wrong, it can describe itself.** `meshterm diagnostics`, or the
Diagnostics page in the menu, puts everything a bug report opens with in one block: which
build this is and how it was installed, the operating system, the terminal and how big it
is, and whether the radio answered. It names nothing private — no keys, no passwords, no
positions, no contacts — and describes your mesh as counts rather than names. One keypress
saves it to a file you can attach to an issue.
- **When something goes wrong, MeshTerm can describe itself.** Run `meshterm diagnostics`,
or open the Diagnostics page in the menu. It puts everything that a bug report starts
with in one block. The block shows which build this is and how it was installed. It shows
the operating system, the terminal and its size, and if the radio answered. It names
nothing private. It has no keys, no passwords, no positions, and no contacts. It shows
your mesh as counts, not as names. One key press saves it to a file that you can attach to
an issue.
### Getting it
One file to download, with nothing else to install, for Windows, macOS (both Intel and
Apple silicon), and Linux (including 64-bit ARM, which covers the uConsole). If you would
rather use Python, `pipx install` works too, on Python 3.10 to 3.14. The README has the
exact commands.
You download one file, and you install nothing else. The files are for Windows, macOS
(Intel and Apple silicon), and Linux (also 64-bit ARM, which covers the uConsole). If you
prefer Python, `pipx install` also works, on Python 3.10 to 3.14. The README has the exact
commands.
MeshTerm is free and open source under the Apache 2.0 licence. The name and the logo are
not covered by the licence (see `NOTICE`), so a fork is welcome under its own name.
MeshTerm is free and open source, under the Apache 2.0 licence. The licence does not cover
the name and the logo (refer to `NOTICE`). A fork is welcome under its own name.
[Unreleased]: https://github.com/jpmartineau/MeshTerm/compare/v0.10.2...HEAD
[0.10.2]: https://github.com/jpmartineau/MeshTerm/releases/tag/v0.10.2