Eine vollständige Ursachenanalyse
MeshDresden · Kategorie: Technik · Zielgruppe: Repeater-Betreiber und fortgeschrittene Nutzer
MeshCore gilt als robust – und ist es auch. Trotzdem gibt es Situationen, in denen Nachrichten lautlos verschwinden: keine Fehlermeldung, keine Bestätigung, kein Hinweis. Wer das zum ersten Mal erlebt, sucht zuerst am falschen Ort.
Dieser Bericht systematisiert alle bekannten Ursachen für Nachrichtenausfälle in MeshCore – vom physikalischen Layer bis zur Firmware-Konfiguration. Viele davon betreffen direkt den path.hash.mode und die damit zusammenhängenden Firmware-Versionen. Andere haben damit gar nichts zu tun, sind aber genauso tückisch.
Überblick: Die Ursachen auf einen Blick
Nachrichtenausfälle in MeshCore lassen sich in fünf Kategorien einteilen:
- Firmware-Inkompatibilität – falscher path.hash.mode trifft alten Repeater
- Uhren- und Timestamp-Probleme – Replay-Protection greift zu Unrecht
- LoRa-Physik und Funkstrecke – Signal kommt schlicht nicht an
- Duty-Cycle und Airtime – der Repeater schweigt aus gesetzlichen Gründen
- Routing- und Konfigurationsfehler – falsche Pfade, flood.max, Regionfilter
1. Firmware-Inkompatibilität durch path.hash.mode
Das Problem
Seit Firmware-Version 1.14 unterstützt MeshCore drei Hash-Größen für den Path-Eintrag im Paket: 1, 2 oder 3 Bytes pro Repeater-Hop. Der Modus wird mit set path.hash.mode <0|1|2> am Repeater gesetzt und bestimmt auch, welchen Modus der Repeater beim Weiterleiten seiner eigenen Adverts verwendet.
Das kritische Problem: Repeater mit Firmware ≤ 1.13 droppen alle Pakete mit 2- oder 3-Byte-Path-Hash kommentarlos. Es gibt keine Fehlermeldung. Die Nachricht verschwindet im Netz, ohne dass Sender oder Empfänger etwas merken.
Die drei Modi im Vergleich
| Modus | Bytes/Hop | Max. Hops (Flood) | Eindeutige IDs | Firmware-Anforderung |
|---|---|---|---|---|
0 | 1 Byte | 63 | 254 | alle |
1 | 2 Bytes | 31 | 65.536 | ≥ 1.14 |
2 | 3 Bytes | 21 | 16.777.216 | ≥ 1.14 |
Der Path ist im Paket auf 64 Bytes begrenzt. Daraus ergibt sich die maximale Hop-Anzahl je Modus: max_hops = 64 / hash_size.
Paketstruktur im Überblick
Das path_len-Byte kodiert Hash-Größe und Hop-Anzahl gemeinsam:
path_len = ((hash_size - 1) << 6) | (hop_count & 63)
Firmware ≤ 1.12 verstand diese Kodierung nicht und droppte Pakete mit mehr als 64 Path-Bytes. Ab 1.14 wird das Feld korrekt interpretiert.
Firmware-Kompatibilitätsmatrix
Wann ist mode 1 oder 2 sicher?
- Für Adverts des Repeaters: Sofort nach Update auf ≥ 1.14 sinnvoll. Analyse-Tools wie LetsMesh.net können Repeater mit 2- oder 3-Byte-Hashes zuverlässiger unterscheiden. Pre-1.14-Repeater droppen diese Adverts, was aber die Netzfunktion nicht beeinträchtigt.
- Für Channel- und Direktnachrichten: Erst dann umstellen, wenn die große Mehrheit der aktiven Repeater im regionalen Netz auf ≥ 1.14 aktualisiert ist. Der Sender legt den Modus fest, nicht der Repeater.
- Companion App: Mode 1 und 2 sind erst ab App-Version 1.41.0 in den experimentellen Einstellungen verfügbar (
Einstellungen → Experimentelle Einstellungen).
Auswirkung auf Nachrichtenlänge
Der nutzbare Textplatz reduziert sich mit steigendem Modus und steigender Hop-Anzahl, bleibt aber in der Praxis unkritisch:
| Hops | Text-Bytes mode 0 | Text-Bytes mode 1 | Text-Bytes mode 2 |
|---|---|---|---|
| 3 | 172 B | 168 B | 162 B |
| 5 | 170 B | 166 B | 160 B |
| 10 | 165 B | 155 B | 139 B |
| 21 | 154 B | 121 B | 84 B |
| 31 | 144 B | 83 B | — |
(Direktnachricht, 9 Byte Overhead für dest_hash + src_hash + MAC + Timestamp + type)
Fazit: Die Nachrichtenlänge ist in der Praxis kein limitierender Faktor. Das entscheidende Problem ist die Firmware-Kompatibilität – nicht die Payload-Größe.
2. Uhren- und Timestamp-Probleme
Dies ist eine der häufigsten und am schwierigsten zu diagnostizierenden Ursachen für Nachrichtenausfälle in autonomen Repeater-Setups.
Wie Timestamps in MeshCore funktionieren
Jede MeshCore-Nachricht enthält einen 32-Bit-Unix-Timestamp (Sekunden seit 1.1.1970). Dieser Timestamp dient zwei Zwecken:
- Replay-Protection: Der Empfänger akzeptiert eine Nachricht nur, wenn ihr Timestamp größer ist als der zuletzt gesehene Timestamp desselben Senders. Nachrichten mit altem Timestamp werden als möglicher Replay-Angriff gewertet und lautlos verworfen.
- Advert-Gültigkeit: Adverts werden ebenfalls anhand ihres Timestamps validiert. Ein Advert mit einem Timestamp in der Vergangenheit wird vom Empfänger ignoriert.
Das Clock-Problem bei autonomem Betrieb
Die vier Fehlerszenarien
Szenario 1 – Neustart ohne Zeitquelle:
Ein Repeater ohne RTC und ohne aktive GPS- oder NTP-Synchronisierung greift nach einem Neustart auf den zuletzt im persistenten Speicher gesicherten Timestamp zurück – sofern ein solcher vorhanden ist. Hatte der Repeater zuvor eine funktionierende Zeitquelle (z.B. eine Remote-Management-Verbindung oder GPS), überlebt dieser Wert den Neustart im Flash und wird als Startzeit verwendet. Fehlt jeder gespeicherte Wert, fällt die Firmware auf einen eingebetteten Fallback zurück – je nach Build das Compile-Datum oder ein hardcodierter Standardwert. In beiden Fällen kann die resultierende Uhrzeit erheblich von der tatsächlichen Zeit abweichen, was dazu führt, dass Adverts und Nachrichten von anderen Knoten als veraltet verworfen werden.
Szenario 2 – Clock drift in die Zukunft:
Wenn ein Repeater-Clock versehentlich in die Zukunft springt, kann die Uhr anschließend nicht mehr rückwärts korrigiert werden – die Firmware akzeptiert keine Clock-Synchronisierung, die die Uhr rückwärts stellt. Einziger Ausweg: vollständiger Stromabbruch inklusive Batterie und Solar.
Szenario 3 – Companion-App synchronisiert falsche Zeit:
Die iOS-App hatte zeitweise einen Bug, bei dem sie die Zeit des Companion-Radios statt der Telefonuhr für die Clock-Synchronisierung eines Repeaters verwendete. War das Companion-Radio nicht korrekt gestellt, bekam der Repeater eine falsche Zeit.
Szenario 4 – Autonomer Repeater ohne Clock-Sync:
Ein Repeater ohne GPS und ohne regelmäßige Remote-Management-Verbindung driftet über Monate. Die Replay-Protection greift zunehmend fehlerhaft, der Repeater wird effektiv aus dem Netz ausgeschlossen – ohne jede Fehlermeldung.
Gegenmassnahmen
| Maßnahme | Aufwand | Wirkung |
|---|---|---|
| RTC-Modul (z.B. DS3231) | mittel | permanente Zeithaltung über Neustarts |
GPS-Modul + gps sync CLI | mittel | sehr genaue Zeit, automatisch |
| Regelmäßige Remote-Management-Verbindung | gering | Clock-Sync via Smartphone |
Cron-Job mit meshcore-cli / Python | mittel | programmatische Synchronisierung |
Für den Funkturm Wilsdruff: Der Repeater läuft solar-powered autonom. Ohne RTC-Modul oder GPS ist ein Clock-Reset nach Stromausfall wahrscheinlich. Empfehlung: RTC-Modul nachrüsten oder in
meshcore-bot-webeine regelmäßige Clock-Synchronisierung per Python-meshcore-Paket implementieren.
3. LoRa-Physik und Funkstrecke
Nicht jeder Nachrichtenausfall hat eine Software-Ursache. Die Physik des LoRa-Übertragungswegs ist mindestens genauso wichtig.
SNR und Empfangsqualität
| SNR | Bewertung | Zuverlässigkeit |
|---|---|---|
| > +5 dB | gut | sehr hoch |
| −5 bis +5 dB | moderat | schwankend |
| < −5 dB | schlecht | Paketverluste wahrscheinlich |
Weitere physikalische Ursachen
Kollisionen durch simultane Übertragungen: LoRa-Pakete belegen die Frequenz für die gesamte Time-on-Air – bei SF12 und 125 kHz Bandbreite können das mehrere Sekunden sein. MeshCore begegnet dem durch randomisierte Weiterleitungsverzögerungen (txdelay), aber in dichten Netzen bleibt Kollision ein relevanter Faktor.
Channel Activity Detection (CAD): Bevor ein Repeater sendet, prüft er ob der Kanal frei ist. Ist er für mehr als 4 Sekunden belegt, verwirft der Repeater das Paket mit einem Timeout-Fehler.
Frequenz- und Parametermismatch: Sender und Empfänger müssen auf exakt denselben Parametern funken (Frequenz, BW, SF, CR). Ein einziges abweichendes Bit führt zu totalem Ausfall ohne jede Rückmeldung.
Verschlüsselungsmismatch: Wenn der empfangende Knoten den falschen Channel-Schlüssel hat, kann er die Nachricht nicht entschlüsseln – sie wird lautlos verworfen.
4. Duty-Cycle, Airtime-Limiter und EU-Regulierung
Das gesetzliche Rahmenproblem
Im EU-Frequenzband 869,525 MHz gilt ein gesetzlicher Duty-Cycle von maximal 10%. Das bedeutet: Pro Stunde darf ein Sender maximal 360 Sekunden senden.
| Einstellung | Effective Duty-Cycle | EU-konform |
|---|---|---|
af = 1 (Default) | ~50% | NEIN |
af = 2 | ~33% | nein |
af = 9 | ~10% | ja |
set dutycycle 10 | 10% | ja |
Wichtig: Der Standardwert
af = 1ist in Deutschland nicht gesetzeskonform. Repeater-Betreiber sind dafür verantwortlich, den korrekten Wert zu setzen.
Wie der Limiter Nachrichten verwirft
Wenn ein Repeater seinen Duty-Cycle ausgeschöpft hat, schweigt er. Er empfängt Pakete, leitet sie aber nicht weiter. Aus Sicht des sendenden Clients sieht es aus wie ein Funkausfall oder ein toter Repeater.
Der neue dutycycle-Befehl (ab Firmware 1.15.0)
set dutycycle 10 # EU-konform, 10% Limit set dutycycle 50 # alter Default (nicht EU-konform) set dutycycle 100 # kein Limit (nur für Tests!)
5. Routing- und Konfigurationsfehler
Veralteter direkter Pfad (stale path)
MeshCore lernt beim ersten erfolgreichen Flood-Durchlauf den direkten Pfad zu einem Knoten und speichert ihn. Fällt ein Repeater im gespeicherten Pfad aus, schlägt die Nachricht dreimal fehl, bevor der Client den Pfad zurücksetzt und erneut flutet. In dieser Übergangszeit kommen Nachrichten nicht an.
flood.max zu niedrig
set flood.max 64 # Default, empfohlen set flood.max 10 # würde Pakete nach 10 Hops still verwerfen
Loop-Detection mit Hash-Kollision
| Stufe | 1-Byte-Hash | 2-Byte-Hash |
|---|---|---|
minimal | ≥ 4× eigene ID verwirft | ≥ 2× eigene ID verwirft |
moderate | ≥ 2× eigene ID verwirft | ≥ 1× eigene ID verwirft |
strict | ≥ 1× eigene ID verwirft | ≥ 1× eigene ID verwirft |
Bei strict mit 1-Byte-Hashes und Kollisionen kann ein Repeater legitime Pakete verwerfen, weil er glaubt, sie bereits gesehen zu haben. Das ist ein direktes Zusammenspiel von Loop-Detection und dem Kollisionsproblem bei mode 0.
Regionfilter und Kanalschlüssel
Ein falsch konfigurierter Regionfilter (REGION_DENY_FLOOD, REGION_DENY_DIRECT) oder ein falscher Channel-Schlüssel führen ebenfalls zu stillen Drops ohne Fehlermeldung.
Diagnose: Systematisches Vorgehen
Schritt 1 – Firmware-Version prüfen
get fw.version
Ziel: alle Repeater im Netz auf ≥ 1.14. Veraltete Firmware ist die häufigste Ursache für stille Drops bei mode 1/2.
Schritt 2 – Clock-Status prüfen
get time
Das Ergebnis sollte einem plausiblen Unix-Timestamp entsprechen (≥ 1.700.000.000 für das Jahr 2023+). Ist der Wert deutlich niedriger, läuft die Uhr falsch.
Schritt 3 – Airtime und Duty-Cycle prüfen
get dutycycle # ab v1.15.0 get af # vor v1.15.0 get stats # TX/RX-Counts, Airtime, Uptime
Schritt 4 – Nachbarn und SNR analysieren
get neighbors
Zeigt die zuletzt gesehenen Nachbarknoten mit Timestamp und SNR (Wert × 4). Ein Repeater ohne Nachbarn hat entweder ein HF-Problem oder ist ausgefallen.
Schritt 5 – Hash-Mode im Netz erfassen
Über LetsMesh.net lässt sich ablesen, welche Repeater 1-, 2- oder 3-Byte-Adverts senden – ohne jeden Repeater einzeln abzufragen.
Zusammenfassung: Ursachen und Gegenmassnahmen
| Ursache | Symptom | Lösung |
|---|---|---|
| path.hash.mode 1/2 + pre-1.14-Repeater | stilles Drop | Firmware-Update oder mode 0 behalten |
| Falsche Repeater-Uhr | Replay-Drop, Advert-Ignore | RTC, GPS oder regelmäßige Clock-Sync |
| Clock in der Zukunft | Sync nicht möglich | Vollständiger Stromabbruch |
| Niedriger SNR | Paketverluste | Antennenoptimierung, Repeater-Positionierung |
| Kollisionen / CAD-Timeout | sporadische Ausfälle | txdelay erhöhen, Kanalauslastung reduzieren |
| Duty-Cycle erschöpft | Repeater schweigt | set dutycycle 10 (EU-konform) |
| Stale Path nach Repeater-Ausfall | 3× Fehlschlag, dann Flood | normales Verhalten, kein Handlungsbedarf |
| flood.max zu niedrig | entfernte Knoten nicht erreichbar | Default 64 verwenden |
| Loop-Detection + Hash-Kollision | Pakete werden verworfen | mode 1 (mehr eindeutige IDs) |
| Falscher Channel-Schlüssel | stilles Drop | Kanalschlüssel auf allen Geräten prüfen |
| Regionfilter | Pakete werden geblockt | Region-Konfiguration prüfen |
Quellen: MeshCore Dokumentation · MeshCore GitHub FAQ · MeshCore CLI Reference · EastMesh Wiki · MeshCore Switzerland Settings · GitHub Issues #1329, #1332, #1882, #2047