1. Inledning & Syfte
Inom digital täckningslös och off-grid kommunikation finns det idag två mycket populära men helt olika ekosystem:
- Meshtastic: Fokuserat på enkla LoRa-radionoder och kanalkommunikation för användare via mobilappar eller WebUI.
- Reticulum Network Stack (RNS) & LXMF: Ett mer avancerat, krypterat och adresserbart nätverksprotokoll byggt för generell datakommunikation, där meddelanden skickas via appar som Sideband, NomadNet och MeshChat.
Syftet med detta projekt var att bygga en tvåvägs mjukvarubrygga körandes på en Linux-nod (Hermes). Bryggan lyssnar på meddelanden i båda nätverken och skickar dem vidare till det andra nätverket.
2. Hårdvara och Mjukvaruarkitektur
Hermes) med Linux Ubuntu/Debian.- Python 3 i en dedikerad virtuell miljö (
/opt/mesh-bridge-venv). RNS&LXMFbibliotek för Reticulum-nätverket.meshtasticPython-bibliotek (medpubsubför händelsestyrd meddelandehantering).systemdför automatisk tjänstehantering och övervakning.
3. Utmaningar och Lärdomar: Från Serieport till TCPÅtervändsgränden: Seriell kommunikation över UART (SerialInterface)
Inledningsvis var planen att bryggan skulle kommunicera direkt med Meshtastic HAT:en via Raspberry Pi:ns interna serieport (/dev/serial0).
- Problemet: UART-kommunikationen visade sig vara instabil vid kontinuerlig drift. Serieportslåsningar, förlorade synkroniseringspaket och konkurrens om hårdvaruresursen gjorde att Python-skriptet ofta tappade kontakten med LoRa-modulen.
- Lösningen: Istället för att låta bryggskriptet prata direkt mot serieporten lät vi den lokala Meshtastic-dæmonen/servicen ta hand om hårdvarugränssnittet. Bryggan ansluter därefter via
TCPInterface(localhost). Detta delade upp ansvaret snyggt och löste alla stabilitetsproblem med hårdvaran.
När vi gick över till TCP dök ett nytt problem upp under nattlig drift. Om TCP-socketen tappades kastades ett BrokenPipeError inuti en av Meshtastic-bibliotekets bakgrundstrådar (sendHeartbeat).
Eftersom felet inträffade i en separat tråd kraschade inte Huvudprocessen i Python, vilket gjorde att systemd inte märkte att tjänsten var död. Skriptet hamnade i ett "zombie-läge".
Detta löstes genom att införa en custom_thread_excepthook:
import threading, sys, logging
def custom_thread_excepthook(args):
logging.error(f"Kritisk krasch i bakgrundstråd {args.thread.name}: {args.exc_value}")
sys.exit(1) # Tvinga processen att avsluta så systemd startar om den
threading.excepthook = custom_thread_excepthook
Tillsammans med en omslutande connect_meshtastic()-loop och systemd-konfiguration har vi nu en tjänst som startar om sömlöst och återansluter automatiskt vid nätverksstörningar.
4. Hur Bryggan Fungerar i Praktiken
Riktning 1: Reticulum (LXMF) $\rightarrow$ Meshtastic
- Bryggan skapar och sparar en permanent LXMF-identitet på disk (
/var/tmp/lxmf_bridge/identity) så att dess 32-teckens LXMF-adress inte ändras vid omstart. - Vid start skickar bryggan ut en
RNS Announceså att klienter som MeshChat och Sideband hittar vägen till bryggan. - När ett LXMF-meddelande tas emot av
LXMRouteravkodas texten och sänds ut som en textbroadcast på Meshtastic-nätet viam_interface.sendText().
Mottagaren on_meshtastic_message analyserar inkommande textpaket från Meshtastic-nätet:
- Broadcast till Reticulum (
#rns):Om ett meddelande innehåller hashtaggen#rns(t.ex.#rns Hallå nätet!), rensas taggen bort och meddelandet skickas som en opportunistisk LXMF-broadcast ut på Reticulum.
Meshtastic: "#rns Test från fältet" ──> LXMF: "[!6ec3d6cc via Mesh]: Test från fältet"
Direktmeddelande via 32-teckens LXMF-hash: Om någon på Meshtastic vill skicka ett riktat meddelande till en specifik LXMF-nod på Reticulum kan de ange adressen i vinkelparenteser:
Meshtastic: "<ea302e71e9840c805e42871d8a82ba77> Hej direkt!"
Bryggan identifierar regex-mönstret, plockar ut máladressen och skickar ett direkt adresserat LXMessage (DIRECT method) på Reticulum.
5. Slutsats & Framtida Utveckling
Genom att kombinera LXMF:s adresserbara och flexibla nätverksprotokoll med Meshtastics enkla LoRa-radioinfrastruktur har vi skapat en robust sömlös brygga mellan två helt olika mesh-världar.
Möjliga framtida utökningar:
- Implementera en alias-ordbok i bryggan för att slippa skriva hela 32-teckens LXMF-adresser från mobilappen (t.ex.
@pelleistället för<ea302e7...>). - Kanalbaserad routning (skicka LXMF till specifika Meshtastic-kanaler beroende på tagg eller avsändare).