meshxt
v0.1.5
Published
MeshXT — Compression & error correction for Meshtastic. Extend your range by 2x.
Maintainers
Readme
MeshXT — Meshtastic Extended
Compression & error correction for Meshtastic — extend your range by 2x
MeshXT preprocesses your Meshtastic messages with intelligent compression and forward error correction, allowing you to send the same data using higher spreading factors for dramatically more range.
🔧 Want to flash your device directly? This is the JavaScript developer library. For a ready-to-flash firmware, see Meshtastic-MeshXT-Firmware — plug in USB, run 4 commands, done.
Installation
npm (for developers)
# Install globally for CLI use
npm install -g meshxt
# Or run directly with npx (no install needed)
npx meshxt encode "Hello world"
# Or add to your project as a dependency
npm install meshxtFrom source
git clone https://github.com/DarrenEdwards111/MeshXT.git
cd MeshXT
npm test # Run 70 tests
npm link # Make CLI available globally (optional)How It Works
Your Message ──→ Compress ──→ FEC Encode ──→ Packet Frame ──→ LoRa Radio
(40-50%) (Reed-Solomon) (2-byte header)
smaller error-proof fits 237 bytesThe key insight: smaller packets = higher spreading factors = more range.
If compression cuts your message in half, you can bump up the spreading factor by one step — roughly doubling your range with the same airtime.
Features
- 🗜️ Smaz Compression — Short-string compression optimised for English text (15-50% savings)
- 📖 Codebook Templates — 74 predefined messages encoded in 1-9 bytes ("I'm OK" = 1 byte)
- 🛡️ Reed-Solomon FEC — Corrects up to 32 corrupted bytes per packet
- 📡 Adaptive SF Selection — Auto-picks optimal spreading factor, bandwidth, and coding rate
- 📦 Packet Framing — Complete packet format that fits Meshtastic's 237-byte limit
- 🔧 CLI Tool — Encode, decode, benchmark, and estimate range from the command line
- 🚫 Zero Dependencies — Pure Node.js, nothing to install
CLI Usage
# Encode a message (shows compression stats + range estimate)
meshxt encode "Are you free for dinner Thursday?"
# Encode with specific options
meshxt encode "Need help" --fec high --compress smaz
# Decode a hex packet
meshxt decode <hex_string>
# Benchmark compression on a message
meshxt bench "Need help at the old bridge, heading south"
# Estimate range for given LoRa parameters
meshxt range --sf 12 --bw 125 --power 14 --antenna 6
# List all codebook templates
meshxt codebook
# Show help
meshxt helpExample Output
$ meshxt encode "Are you free for dinner Thursday?"
📡 MeshXT Encode
─────────────────────────────────
Original: 33 bytes
Compressed: 24 bytes (27.3% saved)
+ FEC (medium): +32 bytes
+ Header: +2 bytes
Total packet: 58 bytes / 237 max
─────────────────────────────────
Recommended: SF12 BW500kHz CR8
Est. range: ~4.3km (2mi)
─────────────────────────────────
Hex: 1120...$ meshxt range --sf 12 --bw 125 --power 14 --antenna 6
📡 MeshXT Range Estimate
─────────────────────────────────
SF: 12
Bandwidth: 125 kHz
TX Power: 14 dBm
Antenna gain: 6 dBi
─────────────────────────────────
Est. range: ~7.3km (4mi)
Link budget: 158.5dB
Sensitivity: -135.5dBmAPI Usage (as a library)
const meshxt = require('meshxt');
// ── Compression ────────────────────────────
const compressed = meshxt.compress('Are you free for dinner Thursday?');
console.log(`Compressed: ${compressed.length} bytes`);
const original = meshxt.decompress(compressed);
console.log(`Decompressed: ${original}`);
// ── Codebook (ultra-compact messages) ──────
// Simple templates (1 byte)
const sos = meshxt.codebook.encode('sos'); // 1 byte
const ok = meshxt.codebook.encode('ok'); // 1 byte
const omw = meshxt.codebook.encode('on_my_way'); // 1 byte
// Parameterised templates
const loc = meshxt.codebook.encode('location', { lat: 51.5074, lon: -3.1791 }); // 9 bytes
const eta = meshxt.codebook.encode('eta', { minutes: 15 }); // 2 bytes
const weather = meshxt.codebook.encode('weather', { type: 'rain' }); // 2 bytes
const battery = meshxt.codebook.encode('battery', { percent: 42 }); // 2 bytes
// Decode
const decoded = meshxt.codebook.decode(loc);
console.log(decoded.text); // "At location [51.507400, -3.179100]"
console.log(decoded.params); // { lat: 51.5074, lon: -3.1791 }
// List all 74 templates
const templates = meshxt.codebook.listTemplates();
// ── Forward Error Correction ───────────────
const data = meshxt.compress('Important message');
const protected_ = meshxt.fec.encode(data, 'medium'); // Add 32 parity bytes
const recovered = meshxt.fec.decode(protected_, 'medium'); // Corrects up to 16 errors
// FEC levels: 'low' (8 errors), 'medium' (16 errors), 'high' (32 errors)
console.log(`Parity bytes: ${meshxt.fec.parityBytes('medium')}`); // 32
console.log(`Max corrections: ${meshxt.fec.maxCorrectableErrors('medium')}`); // 16
// ── Full Packet (compression + FEC + framing) ─
const { createPacket, parsePacket } = require('meshxt/src/packet');
const result = createPacket('Hello from MeshXT!', {
compression: 'smaz', // 'smaz', 'codebook', or 'none'
fec: 'low', // 'low', 'medium', 'high', or 'none'
});
console.log(`Packet size: ${result.packet.length} bytes`);
console.log(`Compression ratio: ${(result.stats.compressionRatio * 100).toFixed(1)}%`);
const parsed = parsePacket(result.packet);
console.log(`Message: ${parsed.message}`); // "Hello from MeshXT!"
// ── Adaptive LoRa Parameter Selection ──────
const rec = meshxt.adaptive.recommend(result.packet.length);
console.log(`Recommended: SF${rec.sf} BW${rec.bw}kHz`);
console.log(`Est. range: ${rec.rangeKm}km`);
console.log(`Airtime: ${rec.airtimeMs}ms`);
// Direct range estimation
const range = meshxt.adaptive.rangeEstimate(12, 125, 14, 6);
console.log(`Range: ${range.rangeKm}km`);
console.log(`Link budget: ${range.linkBudget}dB`);
console.log(`Sensitivity: ${range.sensitivity}dBm`);Using with Meshtastic (Serial/BLE)
If you're building a Node.js app that talks to a Meshtastic device over serial or BLE, here's how to integrate MeshXT:
const meshxt = require('meshxt');
const { SerialPort } = require('serialport'); // npm install serialport
// Connect to your Meshtastic device
const port = new SerialPort({ path: '/dev/ttyUSB0', baudRate: 115200 });
// Sending: compress before sending via Meshtastic serial API
function sendMessage(text) {
const packet = meshxt.createPacket(text, {
compression: 'smaz',
fec: 'low'
});
// Send packet.packet bytes via Meshtastic protobuf serial API
// The receiving end needs MeshXT to decode
console.log(`Sent "${text}" as ${packet.packet.length} bytes (was ${text.length})`);
}
// Receiving: decode incoming MeshXT packets
function onReceive(data) {
const parsed = meshxt.parsePacket(data);
if (parsed.valid) {
console.log(`Received: ${parsed.message}`);
}
}Note: Both sender and receiver need MeshXT. For device-to-device without a computer, use the combined firmware instead.
Range Improvement
| Configuration | Typical Range | Notes | |--------------|--------------|-------| | Stock Meshtastic SF12 | ~50 km | No compression | | + MeshXT Smaz compression | ~80 km | 50% smaller → higher SF viable | | + Reed-Solomon FEC | ~90 km | Decodes at lower SNR | | + Directional antenna | ~200 km | 10dBi Yagi | | Combined | ~200 km / 125 mi | All optimisations |
Compression Benchmarks
| Message | Original | Compressed | Savings | |---------|----------|------------|---------| | "Roger that, heading to your location now" | 40 bytes | 19 bytes | 52% | | "Can you call me when you get this?" | 34 bytes | 21 bytes | 38% | | "Going to the store, do you need anything?" | 41 bytes | 26 bytes | 37% | | "The weather is looking good today" | 33 bytes | 23 bytes | 30% | | "On my way home now, be there in 20 minutes" | 42 bytes | 30 bytes | 29% |
Codebook — Ultra-Compact Messages
| Message | Bytes | |---------|-------| | "I'm OK" | 1 | | "SOS" | 1 | | "On my way" | 1 | | "Need help" | 1 | | "ETA 15 minutes" | 2 | | "Weather: rain" | 2 | | "Battery 42%" | 2 | | "At location [lat, lon]" | 9 |
74 templates covering emergencies, status, navigation, weather, and more.
Packet Format
┌─────────────────────────┬─────────────────────────┬───────────────────┐
│ Header (2B) │ Payload (variable) │ FEC Parity │
├────────┬────────────────┼─────────────────────────┼───────────────────┤
│ Byte 0 │ Byte 1 │ Compressed message data │ Reed-Solomon ECC │
│ │ │ │ │
│ VVVV │ FFFF │ │ 16/32/64 bytes │
│ CCCC │ xxxx │ │ │
└────────┴────────────────┴─────────────────────────┴───────────────────┘
V = Version (4 bits) F = FEC level (4 bits)
C = Compression (4 bits) x = Flags (4 bits)
Total: ≤ 237 bytes (Meshtastic max payload)FEC Error Correction
| Level | Parity Bytes | Corrects Up To | Overhead | |-------|-------------|----------------|----------| | Low | 16 | 8 byte errors | ~10% | | Medium | 32 | 16 byte errors | ~20% | | High | 64 | 32 byte errors | ~40% |
Compile & Runtime Test Results
═══════════════════════════════════════════
C++ Firmware Compile & Runtime Test Results
═══════════════════════════════════════════
Compression Test:
✅ Compress: 33 bytes → 24 bytes (27% saved)
✅ Decompress: "Are you free for dinner Thursday?"
✅ Roundtrip: Perfect match
FEC Test:
✅ Encode: 24 bytes → 40 bytes (+16 parity)
✅ Decode: 24 bytes (clean, no errors)
✅ Roundtrip: Perfect match
Full Packet Test:
✅ Create: 33 bytes → 42 bytes (fits in 237 max)
✅ Parse: "Are you free for dinner Thursday?"
✅ Roundtrip: Perfect match
✅ Valid: YES
═══════════════════════════════════════════
All tests passed — zero warnings, zero errors.
Node.js: 70/70 tests passing.
═══════════════════════════════════════════UK 868 MHz ISM Band
MeshXT is optimised for the UK/EU 868 MHz ISM band:
- Max ERP: 25 mW (14 dBm)
- Duty cycle: 1% (g1 sub-band)
- Adaptive SF selection respects duty cycle limits
Flashing MeshXT to Your Meshtastic Device
⚡ Use the combined firmware repo: Meshtastic-MeshXT-Firmware
MeshXT is a Meshtastic module — it needs the full Meshtastic firmware to run. You can't flash MeshXT on its own. The combined firmware repo gives you Meshtastic + MeshXT in one flash.
Heltec V3 (4 commands):
pip install platformio
git clone https://github.com/DarrenEdwards111/Meshtastic-MeshXT-Firmware.git
cd Meshtastic-MeshXT-Firmware
bash scripts/setup.sh
bash scripts/flash.sh heltec-v3Other devices:
T-Beam, RAK4631, T-Deck, T-Echo — see the full device list and instructions.
C/C++ source files
This repo contains the MeshXT module source code in firmware/src/ (8 files, ~967 lines). These are the files that get integrated into the Meshtastic firmware build. For manual integration details, see the firmware repo.
Project Structure
meshxt/
├── package.json # Zero dependencies
├── README.md
├── LICENSE # Apache 2.0
├── src/
│ ├── index.js # Main entry point
│ ├── compress.js # Smaz-style text compression
│ ├── codebook.js # 74 predefined message templates
│ ├── fec.js # Reed-Solomon GF(2^8) FEC
│ ├── adaptive.js # LoRa parameter optimisation
│ ├── packet.js # Packet framing (header + payload + FEC)
│ └── utils.js # Helpers
├── bin/
│ └── longshot.js # CLI tool
└── test/
└── test.js # 70 tests, all passingRequirements
- Node.js >= 16.0.0
- No external dependencies
License
Apache 2.0 — Copyright 2026 Darren Edwards
Contributing
PRs welcome! Key areas for contribution:
- C/C++ port for direct Meshtastic firmware integration
- Improved compression codebook for non-English languages
- Adaptive FEC that adjusts based on link quality
- Real-world range testing and validation
- Python port for MicroPython on ESP32
Get in Touch
- 🐛 Bug reports — GitHub Issues
- 💡 Ideas, questions & development discussion — GitHub Discussions
- 📧 Contact — [email protected]
Links
- npm: https://www.npmjs.com/package/meshxt
- GitHub: https://github.com/DarrenEdwards111/MeshXT
- Firmware: https://github.com/DarrenEdwards111/Meshtastic-MeshXT-Firmware
- Issues: https://github.com/DarrenEdwards111/MeshXT/issues
- Discussions: https://github.com/DarrenEdwards111/MeshXT/discussions
