A simple file transfer system for Meshtastic mesh networks, enabling file sharing between nodes over long-range radio links.
MeshFTP consists of two components:
- Server: Serves files from a directory to other mesh nodes
- Client: Downloads files from a server node on the mesh network
Files are chunked, base85-encoded, and transferred over Meshtastic direct messages (DMs) with automatic retry logic and MD5 checksum validation.
MeshFTP is designed for small files due to Meshtastic's low bandwidth and DM size limitations. It is ideal for sharing text files, small images, or configuration files in remote areas without internet access.
Be kind, remember everyone's bandwidth is limited and transferring large files may impact other users on the mesh. That said, MeshFTP monitors channel utilization and will automatically back off when the network is busy.
Install using uv:
# Clone the repository
gh repo clone richstokes/MeshFTP
cd MeshFTP
# Install dependencies
uv syncStart a file server to share files with other nodes:
uv run mftp-server -d /path/to/filesOptions:
-d, --directory(required): Directory containing files to serve
Example:
uv run mftp-server -d ./example_filesOn startup, the server will:
- Show available Meshtastic devices (serial and Bluetooth)
- Let you select a device
- Process and chunk all files in the specified directory
- Display its node ID (e.g.,
!abcd1234) - Listen for file requests from clients
Supported Commands:
!ls- List available files!req <filename> <chunk>- Request a specific file chunk!check <filename>- Request MD5 checksum for validation
Download files from a server node using the interactive TUI client:
uv run mftp-client -s <server-node-id> [-d <download-directory>]Options:
-s, --server(required): Server node ID to connect to (e.g.,!abcd1234orabcd1234)-d, --directory(optional): Download directory (default:~/Downloads/MFTP)
Note: Terminals will often try and interpret the
!character, so either escape it (e.g.,\!abcd1234) or omit it when specifying the server node ID.
Example:
# Use default download directory
uv run mftp-client -s abcd1234
# Specify custom download directory
uv run mftp-client -s abcd1234 -d ./my-downloadsOn startup, the client will:
- Show available Meshtastic devices
- Let you select a device
- Connect to the mesh network
- Enter interactive mode, letting you list and download files from the server
MFTP uses Meshtastic direct messages with a simple command protocol:
Client → Server:
!ls- Request file list!req <filename> <chunk_number>- Request specific chunk!check <filename>- Request file checksum
Server → Client:
{"files":[{"name":"file.txt","chunks":5},...]}- JSON file list!chunk <filename> <chunk_number> <base85_data>- File chunk response!checksum <filename> <md5_hash>- Checksum response!error <message>- Error message
- Client sends
!lsto request file list - Server responds with JSON containing available files
- Client displays files and user selects one
- Client requests chunks sequentially with 30-second timeout
- Server sends each chunk as base85-encoded data
- Client retries failed chunks up to 5 times with exponential backoff
- After all chunks received, client reassembles and saves file
- Client requests checksum and validates downloaded file
- Transfer complete if checksum matches
- Files are split into 150-byte chunks (after base85 encoding)
- Chunk size chosen to fit within Meshtastic DM payload
- Each chunk is transmitted independently with error handling
- Progress displayed as "Chunk X/Y" during download
-
Maximum filename length: 10 characters
- Required to fit file list in Meshtastic DM payload
- Files with longer names are skipped with a warning
-
Maximum files per directory: 4 files
- Limited by Meshtastic DM payload for
!lsresponse - With 10-char filenames, only 4 files fit in JSON list
- Excess files are ignored with a warning message
- May implement pagination for larger file lists in future
- In practical terms, it works best with just a few small files in a dedicated directory
- Limited by Meshtastic DM payload for
- Transfer speed: Very slow - Meshtastic has low bitrate (LoRa is long-range, not high-speed), mesh network adds latency for multi-hop routes, expect minutes for small files
- Sequential chunks only: No parallel chunk download
- Contention: MeshFTP automatically watches ChUtil and slows down when the network is busy
- Retry logic: 10 attempts per chunk with 30-second timeout and exponential backoff
- Checksum validation: MD5 hash verification after download
- Packet deduplication: Handles mesh network rebroadcasts
- No guaranteed delivery: Mesh networks are unreliable
- Obstacles, distance, interference can cause failures
- Transfer may fail if connection is lost
- No authentication: Anyone on the mesh can access served files
- No encryption: Files transferred in plaintext (base85 encoded). I don't fully understand if/how Meshtastic encrypts DMs so send at your own risk!
- No compression: Files sent as-is, no size optimization - compress your files first
- No directory browsing: Only serves files from one directory
- No file upload/deletion: Server directory is read-only
- No directory refresh: Files are loaded on server startup only, restart to update
- Keep filenames short (10 chars or less, including extension)
- Serve only a few files (4 maximum) at a time
- Use small files for realistic transfers
- Encrypt files first if privacy is a concern
