Repository navigation
LoRa and Meshtastic
Knit works phone to phone out of the box, over Bluetooth and Wi-Fi Aware, with hops of tens of metres. Pair a Meshtastic LoRa board with your phone and Knit gets a second kind of hop that can cross kilometres of open ground. The board is optional, and nothing goes out over it until you pair one, set it up and turn LoRa on.
This page covers what Knit sends over the board, how it shares the air, and what a listener on the band can see. It builds on How a message crosses the mesh.
Checked against Knit 2.11.0-beta.0.
LoRa is a radio modulation that trades speed for range on very little power. On Meshtastic's default LongFast preset, a full-size packet of about 230 bytes takes around two seconds to send, and a short direct message about one second.
The air is shared, too. Every board in range on the same frequency and preset hears every packet, and only one can transmit at a time without collisions. Some regions also limit by law how much of each hour a radio may transmit, the duty cycle: 10 % in Meshtastic's EU 868 region, 100 % in the US, where the community still expects each node to keep its share small. Knit keeps LoRa for short, time-sensitive messages.
Knit connects to the board over Bluetooth Low Energy through Meshtastic's own phone interface, the one the Meshtastic app uses. You pair the board in Android's Bluetooth settings first, then pick it in Knit under Profile › LoRa radio. A board serves one phone at a time, so the Meshtastic app has to let go of it.
Knit's packets use the PRIVATE_APP port, so stock Meshtastic apps don't show them as text, and every packet states a hop limit of 3. Firmware 2.8 reads a missing hop limit as zero, which would stop any other board repeating it. When the board drops out, Knit tries three direct reconnects, then lets Android's Bluetooth controller reconnect at low power once the board advertises again.
The "Set up this board for Knit" button configures the board through Meshtastic's admin interface in one transaction:
- It adds a secondary channel called Knit in the first free slot. The primary channel, slot 0, is never touched.
- It stretches the board's node info, position and telemetry broadcasts to every 6 hours.
- It sets the rebroadcast mode to
LOCAL_ONLY, so the board keeps repeating its own channels, Knit's included, and stops repeating channels it can't decrypt. - It renames the board "Knit abcd" (short name "Knit"), never your own name, and on firmware 2.6.9 and later marks it unmessagable.
Restore puts back everything the setup changed.
The Knit channel's key is derived from a public value, so every Knit board has the same one and any two meet without exchanging anything. With the primary channel left alone, a stock board stays on the public frequency, where Meshtastic nodes on their default rebroadcast mode repeat Knit's packets without being able to read them. Two boards only hear each other on the same modem preset, which Knit leaves to you, and renaming the primary channel moves the radio to another frequency. The radio screen points out both.
In the US, Australia and New Zealand you can choose "Set up on a dedicated frequency" instead. It does everything above and also pins the radio to a slot derived from the channel name, so every Knit board set up this way lands on the same one. Stock nodes no longer relay your packets there, and in return Knit lifts its own politeness cap (see below).
The board sends only what you wrote. Everything it hears goes into the phone mesh as usual.
| Carried over LoRa | Stays on the phone radios, catch-up and relays |
|---|---|
| Your own Nearby room posts that fit one packet, within 15 minutes of writing them | Longer room posts, replies and anything with an attachment |
| Your direct messages that fit one packet, to contacts whose board Knit knows | Group chats, and every group change and key |
| Delivery ticks and reactions for those direct messages | Room reactions and room delivery ticks |
| Pictures, voice notes and files | |
| Profiles, typing indicators, and anything someone else wrote |
LoRa carries an extra copy: every message still travels the phone mesh and any relay you use, exactly as without a board. When the person you're writing to was last heard only over LoRa, the chat says which kinds of message won't reach them that way.
A Meshtastic packet holds at most 231 bytes of Knit data, or 228 until the board reports its Bluetooth packet size. Nothing Knit sends over LoRa is split across packets.
A Nearby room post goes out as the same signed message the phone radios carry, compacted and compressed, with the author's signature unchanged so any Knit phone can verify it. With the signature and header inside, one packet holds about 100 bytes of text that won't compress, more of ordinary prose, and the composer warns past that point. Firmware 2.8 adds its own 66-byte signature to broadcasts small enough to take one, so Knit pads a post a few bytes past that size where that saves airtime.
A direct message goes as a compact copy sealed for one recipient, in one packet addressed to their board. Meshtastic's encryption caps that packet at 219 bytes, and Knit's seal and header take 51 of them, leaving 168 for the message. The composer's hint for a DM is 160 bytes of text. A quoted reply or an attachment reference doesn't fit in what's left, so a DM with either stays off LoRa.
A DM rides LoRa only to a contact whose profile names their board and says their version of Knit takes compact DMs. It goes as a Meshtastic unicast that asks for an acknowledgement, and on firmware 2.8 the board retries it up to four more times if none comes back. Knit skips LoRa when the phone radios have a live link to that contact, or a relay heard from them in the last 15 minutes, since that copy arrives anyway.
Your chat shows two stages. When their board acknowledges the packet, the message shows the LoRa mark beside one tick: "Reached their LoRa radio". That's the radio answering, and their phone might not be connected to it. The second tick comes when their phone has the message. The receiving phone batches up to nine ticks into one packet.
A board can lose a packet while no phone is connected to it, so for a DM still without its second tick, Knit sends it again 15 minutes later, then at gaps that double up to every 4 hours, until the tick arrives.
If your board refuses a DM because it lacks the public key of the contact's board, Knit can write that key to it from the contact's Knit profile. The contact then shows as a favourite in Meshtastic apps connected to your board.
Knit budgets its own airtime over a rolling 15-minute window. The allowance is the lower of your region's duty cycle and a 10 % politeness cap, halved for safety:
| Board | Knit's allowance per 15 minutes |
|---|---|
| US, EU 868 and most regions, shared frequency | 45 seconds (5 %) |
| EU 866 (2.5 % duty cycle) | about 11 seconds |
| US, Australia or New Zealand, dedicated frequency | 7.5 minutes (half of the 100 % the region allows) |
At LongFast, 45 seconds is roughly 20 full-size packets. Each packet is priced with the firmware's signature and encryption overhead included. A DM is admitted only if all five of its possible airings fit, and the unused ones are refunded when the recipient's board answers. The firmware enforces the legal duty cycle itself, and when it refuses a send, Knit backs off for a minute.
Packets leave at least 3 seconds apart. DMs, their ticks and reactions go before room posts, and a full queue of 32 drops room posts first. Your room posts also wait while the board reports its channel at least 40 % busy, the level where Meshtastic firmware holds back its own routine traffic, and a post still waiting 15 minutes after you wrote it doesn't go over LoRa. Posts to the Meshtastic room and the auto-reply described below go out only while Knit's total stays under half the allowance. The radio screen shows how much of the window is spent, and a chat says when the budget or a busy channel is delaying someone reachable only over LoRa.
When your board hears a room post from far away, your phone handles it like any other message and passes it on over Bluetooth and Wi-Fi Aware, so friends without a board see it too.
flowchart LR
F["Far phone"] -->|Bluetooth| FB["Far board"]
FB -->|"LoRa, kilometres"| YB["Your board"]
YB -->|Bluetooth| Y["Your phone"]
Y -->|"Bluetooth or Wi-Fi Aware"| N["Friend without a board"]
Your board doesn't send your friend's posts, though. Theirs reach the far side through phones, a relay, or someone walking over. A LoRa DM goes to one board and its phone, so a contact without a board gets nothing over LoRa. Profiles don't ride LoRa either, so a post from someone your mesh has never had a profile from waits for one before it's shown.
Anyone with a radio on the same frequency and preset can record what Knit sends. Nearby room posts are plaintext by design, on LoRa as on the phone radios, and the Knit channel key is public, so a listener running Knit's code can read them. Each post is still signed, so nobody can alter it or post under your name.
Direct messages, their ticks and their reactions stay sealed. Knit seals the compact copy with a key only you and the contact share, derived from your two Knit identity keys, and Meshtastic firmware 2.8 wraps it again in PKI encryption to the recipient's board. That pair key doesn't change, so unlike the copy on other paths, which the ratchet seals, the LoRa copy has no forward secrecy. The outside of the packet stays visible at kilometre range: your board's node number, the recipient's board, the time and the size. Your Knit profile names your board's node number, so anyone holding your profile can match the board to you.
The "Private messages over LoRa" switch on the LoRa radio screen is on by default. Off, your phone sends no DMs over LoRa and stops telling contacts that your board takes them. Your Nearby posts still ride LoRa, and your DMs keep travelling every other way.
Pairing a board also adds a Meshtastic room to your chat list, a mirror of the board's primary channel with whatever preset, name or key you gave it. You can read what other Meshtastic users post there and reply. These posts never enter Knit's mesh, so a phone without a board doesn't see them.
The room sits outside Knit's encryption: the stock channel key is public, and a custom key is shared by every radio holding it. After a one-time notice, your posts go out under the board's name, "Knit abcd", with no author name added and at most one every 30 seconds.
Anyone can claim any name there. Knit matches a post to a contact by the board number in their profile and shows it as unverified, unless their board signed it (firmware 2.8.1 and later) and the signature checks out against the board key in their profile, which adds a shield. A switch hides the room, and a board on a dedicated frequency has none, since no public radio can hear it.
Knit only reads Knit traffic, so when a Meshtastic user DMs your board, Knit answers once per sender per day with a fixed line saying the node is unmonitored and part of a Knit mesh.
- LoRa bridge reference has the full mechanism, firmware measurements included.
- LoRa decision index maps each part of the code to the decisions behind it.
- The LoRa plane's code is where to start reading the source.
- What Knit encrypts, and what stays visible covers encryption across the app.
- Meshtastic radio settings explains presets, regions and channels from Meshtastic's side.
- The radios Knit uses and What an Internet relay can see cover the other paths.
Knit is free and ad-free, funded by its supporters.
☕ Ko-fi ·
💖 GitHub Sponsors ·
Liberapay ·
Other ways to help
Supporting Knit on Ko-fi or GitHub Sponsors comes with Knit Anywhere. Liberapay goes to the developer personally.