Mesh Protocol

A technical overview of how Socialmesh extends the Meshtastic radio protocol to support presence beacons, compact signals, and node identity exchange — without modifying firmware.

Contents

1. Overview

Socialmesh is a companion app for Meshtastic mesh radios. It adds features that the stock Meshtastic app does not provide: presence awareness, broadcast signals with expiry, and a node identity system called NodeDex.

These features need to send data over the mesh. Rather than forking Meshtastic firmware, Socialmesh uses private portnums — a range (256–511) that Meshtastic reserves for third-party applications. Stock firmware routes packets on private portnums identically to any other packet. No firmware changes are required.

Socialmesh defines three new packet types, each on its own portnum:

Portnum Name Purpose
260 SM_PRESENCE "I am here" beacon
261 SM_SIGNAL Broadcast signal (alert, notice)
262 SM_IDENTITY Node identity digest (sigil, trait)

A fourth portnum, 256, carries legacy JSON-encoded signals for backward compatibility with older Socialmesh releases.

All three new packet types use hand-packed binary encoding rather than protobuf. The result is smaller payloads, less airtime, and more room on the mesh for everyone.


2. Why Binary?

LoRa is a slow, shared radio channel. Every byte costs airtime, and airtime is the scarcest resource on a mesh network. The original Socialmesh signal format used JSON on portnum 256. A typical signal with a short message and GPS coordinates consumed roughly 130 bytes.

The binary encoding reduces this to about 50 bytes — a 60% reduction. Presence beacons, which previously had to piggyback on full signal payloads, shrink to as little as 3 bytes.

Use Case JSON (Legacy) Binary Reduction
Signal with GPS + short text ~130 bytes ~50 bytes ~60%
Signal without GPS ~80 bytes ~30 bytes ~62%
Presence beacon with GPS ~130 bytes ~12 bytes ~91%
Node identity exchange N/A ~9 bytes (new)

The encoding is also deterministic. Every field has a fixed size and position (conditionally present based on flags), which makes byte budgets easy to enforce and decode logic trivial.


3. Packet Families

portnum 260

SM_PRESENCE

An ephemeral "I am here" beacon. A node broadcasts its presence periodically to let nearby nodes know it is active. A presence packet can optionally include:

Presence is local by default. Packets use a low hop limit (2 hops) and background priority, so they stay within the immediate neighborhood and yield to higher-priority traffic under congestion.

There is no mesh-enforced TTL. The receiving app applies confidence decay: a node is "active" for 2 minutes after a beacon, "fading" until 10 minutes, and "stale" after 60 minutes.

Typical size: 3–75 bytes depending on optional fields.

portnum 261

SM_SIGNAL

A broadcast signal — a short, expiring message intended for all nodes in range. Signals can carry:

Each signal carries an 8-byte random ID used for deduplication and cloud sync mapping.

Priority Hop Limit Acknowledgment
Normal 3 No
Important 3 No
Urgent 3 Yes
Emergency 5 Yes

TTL is strictly a client-side display hint. The mesh has no mechanism to enforce expiry or recall a broadcast. Receiving apps use the TTL class to decide when to stop showing the signal.

Typical size: 21–159 bytes depending on content length and optional fields.

portnum 262

SM_IDENTITY

A compact identity digest used by the NodeDex system. Nodes exchange:

Identity supports a request/response protocol:

  1. Request: Node A asks Node B for its identity (unicast, 6 bytes)
  2. Response: Node B replies with its full digest (unicast, 6–9 bytes)
  3. Unsolicited broadcast: A node announces itself on first appearance or trait change

Unsolicited identity broadcasts use a hop limit of 1 (direct neighbors only). Requests and responses use a hop limit of 3 to reach specific nodes.

Typical size: 6–9 bytes.


4. The Header Byte

All three packet types share a common first byte, called hdr0:

hdr0 = (version << 4) | kind

This gives room for 16 protocol versions and 16 packet kinds with zero additional overhead — a single byte.

The second byte is always a flags byte. Its layout is specific to each packet kind, controlling which optional fields are present. Together, the two-byte header tells the decoder everything it needs to parse the rest of the payload.

Version tolerance: If a receiver encounters a version higher than it supports, it silently discards the packet. Unknown kind values are also silently discarded. This allows future protocol revisions to coexist on the same mesh without breaking existing implementations.


5. Signal IDs & Collision Probability

Each SM_SIGNAL carries an 8-byte (64-bit) random identifier generated by a cryptographically secure random number generator. This ID serves two purposes:

  1. Deduplication. The mesh naturally rebroadcasts packets. The signal ID lets receivers discard duplicates they have already processed.
  2. Cloud sync mapping. For users who optionally sync signals to the cloud, the app maps the 64-bit wire ID to a local UUID.

The ID is not a secret — it travels in the clear alongside the signal content. Its purpose is uniqueness, not secrecy. A 64-bit random ID saves 28 bytes per signal compared to a string UUID, which matters when every byte costs airtime.

Collision probability

The birthday-bound formula gives the probability that at least two signals in a set of n share the same 64-bit ID:

P ≈ n2 / 265
Signals Collision Probability
1,000 ~2.7 × 10−14
100,000 ~2.7 × 10−10
1,000,000 ~2.7 × 10−8 (1 in 37 million)

At the throughput of a LoRa mesh network, these volumes would take years to accumulate. Collisions are negligible.


6. Compatibility & Migration

Stock firmware compatibility

Socialmesh extensions require no firmware changes. The relationship is straightforward:

Component Awareness Behavior
Stock Meshtastic firmware None Routes and relays SM packets normally
Stock Meshtastic app None Silently ignores SM portnums
Older Socialmesh app Partial Handles portnum 256 (legacy JSON) only
Current Socialmesh app Full Handles portnums 256, 260, 261, 262

Stock firmware relays packets on portnums 260–262 just as it relays any other packet. It does not need to understand the payload. The routing layer is portnum-agnostic.

Peer capability detection

Socialmesh detects capable peers passively. When a node sends any packet on portnums 260–262, it reveals itself as a Socialmesh node. The app tracks this per-node — no explicit handshake or beacon is needed.

Dual-send migration

During the transition period, the app can operate in dual-send mode: it sends both a binary SM_SIGNAL (portnum 261) for current peers and a legacy JSON signal (portnum 256) for older peers. Both formats carry the same content and map to the same signal ID, so the receiving app deduplicates them into a single item regardless of which encoding arrives first.

Dual-send increases airtime by roughly 38% during the migration window. Once all peers on the mesh are detected as SM-capable, legacy sending can be disabled.

Mode Binary (261) Legacy JSON (256) When to Use
Legacy only No Yes Before binary support ships
Dual-send Yes Yes Mixed mesh, some peers not upgraded
Binary only Yes No All peers confirmed SM-capable

Minimum firmware version: Private portnum support (260–262), the BLE/USB API, and channel encryption have been stable since Meshtastic firmware 2.0. No minimum beyond 2.0 is required.


7. Design Principles

Pure extension, no fork. All Socialmesh logic lives in the app. The firmware is unmodified. This means zero rebase cost when Meshtastic releases a new firmware version, and zero risk of breaking upstream compatibility.

Conservative airtime. Every packet type has app-enforced rate limits. Presence beacons are limited to once per 5 minutes. Signals have a 30-second minimum interval. Emergency signals are capped at 3 per hour. These limits exist to be good neighbors on a shared radio channel.

Graceful degradation. If a receiving node does not understand a Socialmesh packet, nothing bad happens — the packet is silently ignored. If a sending node cannot detect any SM-capable peers, it falls back to legacy JSON. The app never assumes the entire mesh runs Socialmesh.

Byte budgets, not MTU promises. All content limits (63 bytes for presence status, 140 bytes for signal content) are enforced at encoding time, well below the LoRa payload ceiling. This provides headroom for radio overhead and avoids fragmentation.

Client-side expiry. TTL values on signals are display hints for receiving apps. The mesh has no mechanism to enforce expiry or recall a broadcast. This keeps the protocol stateless and avoids complexity in the relay layer.

Deterministic encoding. Binary fields have fixed sizes and positions. There are no variable-length integers, no field tags, no schema negotiation. A decoder needs only the flags byte to know which fields are present.

Version tolerance. Unknown protocol versions and unknown packet kinds are silently dropped. This allows the protocol to evolve without coordination across all nodes on a mesh.


8. For Developers

Interoperability

If you are building an app or tool that operates on a Meshtastic mesh alongside Socialmesh nodes, here is what to expect:

Decoding SM packets

Every SM packet starts with a one-byte header (hdr0). To identify the packet type:

version = (hdr0 >> 4) & 0x0F
kind    = hdr0 & 0x0F

If version is higher than you support, discard the packet. If kind is not one you recognize, discard the packet. Otherwise, read the flags byte (byte 1) and decode the remaining fields based on the kind.

All multi-byte integers are big-endian. All strings are UTF-8 with a one-byte length prefix counting bytes, not characters.

Rate limit expectations

Packet Type Minimum Interval
Presence beacon 5 minutes
Signal broadcast 30 seconds
Identity broadcast 30 minutes
Identity request 10 minutes (per target node)
Emergency signal 3 per hour max

These are app-side limits, not mesh-enforced. A misbehaving implementation could exceed them, but the firmware's duty cycle enforcement provides a hard backstop regardless.

This page is the public specification for the Socialmesh mesh protocol. Questions or interoperability concerns? Reach out via the support page.