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:
1 parent
26d422e651
commit
bc51115d24
1 file changed
+234
-202
+234
-202
@@ -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
|
||||
|
||||
Reference in new issue
Block a user