MeshCore message formats & payloads
Technical deep-dive into the structure of MeshCore messages, Protobuf encoding and payload formats for efficient LoRa communication
How MeshCore messages are structured
MeshCore uses an efficient message structure to send data over the LoRa mesh network. Each message consists of a header with metadata and a payload with the actual content. By using Protocol Buffers (Protobuf), messages remain compact and structured.
The message formats are designed for low-bandwidth communication. LoRa has limited throughput (typically 100-300 bytes per message), so efficiency is crucial. MeshCore compresses data intelligently and uses binary encoding instead of text-based formats like JSON.
In this technical guide, we explain how MeshCore messages are structured, what message types exist, and how payloads are encoded for optimal performance in the mesh network.
Protocol Buffers (Protobuf) structure
MeshCore uses Google's Protocol Buffers for message serialization. Protobuf is a binary format that is much more efficient than JSON or XML. An example of a MeshCore message definition:
message MeshPacket {
uint32 from = 1; // Sender node ID
uint32 to = 2; // Receiver node ID
uint32 id = 3; // Unique message ID
bytes payload = 4; // Encoded data
uint32 hop_limit = 5; // Max number of hops
bool want_ack = 6; // ACK request
uint32 rx_time = 7; // Reception timestamp
}
Each field has a tag number (1, 2, 3, etc.) for compact encoding. Protobuf only stores fields that have a value (optionals), which saves space. A typical MeshCore message is only 20-50 bytes without payload.
MeshCore message types
TEXT_MESSAGE
Text messages between users. Max 200 characters plain text. Most commonly used message type for communication.
POSITION
GPS coordinates (latitude, longitude, altitude). Updates location of nodes on the map. Sent periodically.
TELEMETRY
Sensor data: battery voltage, temperature, humidity. For monitoring nodes and environmental data.
NODEINFO
Node information: name, hardware model, firmware version. Sent at startup and periodically for network discovery.
ROUTING
Routing information and network topology updates. Used by the flooding algorithm for efficient message delivery.
ADMIN
Administrative commands: change configuration, reboot, channel settings. Only for authorized nodes.
Payload structure and encoding
Packet header (overhead)
Each MeshCore packet has a header of ~20 bytes with metadata:
- <strong>From/To</strong> - Node IDs (32-bit integers)
- <strong>Packet ID</strong> - Unique number for duplicate detection
- <strong>Hop limit</strong> - Number of remaining hops (default 3, max 7)
- <strong>Flags</strong> - want_ack, encrypted, etc.
Payload data
The payload contains the actual content, encoded as Protobuf bytes. Maximum payload size is ~230 bytes (depending on LoRa spreading factor). Encrypted payloads use AES-256 with a shared channel key.
Technical specifications
| Parameter | Value | Description |
|---|---|---|
| Max packet size | 256 bytes | LoRa PHY layer limit (SF7/8) |
| Header overhead | ~20 bytes | Protobuf header with routing info |
| Max payload | ~230 bytes | After deducting header overhead |
| Text message max | 200 chars | UTF-8 encoded, practical limit |
| Encoding format | Protobuf 3 | Binary, backward compatible |
| Encryption | AES-256-CTR | Per-channel PSK encryption |
Benefits of MeshCore message formats
Extremely compact
Protobuf encoding is 3-10x smaller than JSON. Essential for low-bandwidth LoRa communication.
Backward compatible
New fields can be added without breaking old clients. Protobuf schema evolution.
Type-safe
Strict type checking prevents parsing errors. Fewer bugs than loosely-typed formats.
Fast parsing
Binary format is much faster to parse than text-based formats. Important for low-power devices.
Multi-platform
Protobuf libraries available for C++, Python, JavaScript, Go, etc. Easy to build clients.
Extensible
Custom payload types can be easily added for specific use cases.
Frequently asked questions
Why does MeshCore use Protobuf instead of JSON?
Protobuf is 3-10x more compact than JSON and faster to parse. LoRa has very limited bandwidth (~300 bytes/s), so every byte counts. JSON would have too much overhead for a mesh network.
What is the maximum length of a text message?
Text messages are limited to 200 characters. This fits comfortably within the ~230 byte payload limit (UTF-8 encoding). Longer messages must be split.
Are all messages encrypted?
No, only messages on private channels with a PSK (Pre-Shared Key) are encrypted with AES-256. Public channels are unencrypted. You can configure encryption per channel.
Can I add custom message types?
Yes, MeshCore supports custom port numbers for your own payloads. You can define your own Protobuf messages and send them via port numbers 256-511. See the plugin development documentation.
How do I know which message format a node supports?
Each node sends a NODEINFO message at startup with its firmware version. Protobuf is backward compatible, so new fields are ignored by old firmware. Forward compatibility is guaranteed.
What happens if a message is too large?
Messages larger than ~230 bytes are truncated or rejected by the firmware. You will receive an error. Split long data into multiple messages or use data compression.
Start with MeshCore development
Now that you know how MeshCore messages are structured, you can start developing your own applications and plugins.