Meshtastic

The MeshtasticNode component is a minimal, radio-agnostic implementation of the Meshtastic® over-the-air mesh protocol, sufficient to interoperate with stock Meshtastic devices on a shared channel (the public “LongFast” channel by default). It handles framing, AES-CTR encryption with the well-known default channel key, sending and receiving text messages / node info / positions, receive-side deduplication, and optional managed-flood rebroadcasting.

It is decoupled from any particular radio - you provide a transmit function and feed it received frames - and pairs naturally with the SX126x LoRa Radio component.

Note

This is an independent, clean-room implementation of the published Meshtastic protocol; it is not affiliated with or endorsed by Meshtastic LLC. “Meshtastic” is a registered trademark of Meshtastic LLC. See the component README for licensing and trademark details.

API Reference

Header File

Classes

class MeshtasticNode : public espp::BaseComponent

A minimal, radio-agnostic Meshtastic-compatible mesh node.

This class implements enough of the Meshtastic over-the-air protocol to interoperate with stock Meshtastic devices on a shared channel (the public “LongFast” channel by default): it frames, encrypts (AES-CTR with the well-known default key), sends and receives text messages, node info and positions, and performs receive-side deduplication and (optionally) managed-flood rebroadcasting.

It is decoupled from any particular radio: you provide a transmit function and feed it received frames (e.g. from an espp::Sx126x driver). Call modem_config() to get the exact LoRa modulation parameters to apply to your radio for the configured region / preset / channel.

Example

  // build the mesh node, transmitting through the radio
  auto node = std::make_shared<espp::MeshtasticNode>(espp::MeshtasticNode::Config {
    .long_name = CONFIG_EXAMPLE_LONG_NAME, .short_name = CONFIG_EXAMPLE_SHORT_NAME,
#if CONFIG_EXAMPLE_HARDWARE_TDECK
    .hw_model = espp::meshtastic::HardwareModel::T_DECK,
#elif CONFIG_EXAMPLE_HARDWARE_CARDPUTER_ADV
      .hw_model = espp::meshtastic::HardwareModel::M5STACK_CARDPUTER_ADV,
#endif
    .region = REGION, .preset = espp::meshtastic::ModemPreset::LONG_FAST,
    .transmit = [radio](std::span<const uint8_t> frame) -> bool {
      std::error_code ec;
      bool ok = radio->transmit(frame, 5s, ec);
      if (!ok) {
        // returning to receive is handled by transmit(); log failures
      }
      return ok;
    },
#if CONFIG_EXAMPLE_REBROADCAST
    .rebroadcast = true,
#else
      .rebroadcast = false,
#endif
    .on_text =
        [&](const std::string &text, const espp::meshtastic::PacketMetadata &meta) {
          logger.info("[TEXT] from 0x{:08x} ({} hops, SNR {:.1f}): {}", meta.header.from,
                      meta.hops_taken, meta.snr, text);
        },
    .on_nodeinfo =
        [&](const espp::meshtastic::User &user, const espp::meshtastic::PacketMetadata &meta) {
          logger.info("[NODE] 0x{:08x} is '{}' ({})", meta.header.from, user.long_name,
                      user.short_name);
        },
    .on_position =
        [&](const espp::meshtastic::Position &pos, const espp::meshtastic::PacketMetadata &meta) {
          logger.info("[POS ] 0x{:08x} @ {:.5f}, {:.5f}", meta.header.from, pos.latitude(),
                      pos.longitude());
        },
    .log_level = espp::Logger::Verbosity::INFO,
  });

  // deliver received radio packets to the mesh node
  radio->set_receive_callback([node](const espp::Sx126x::RxPacket &packet) {
    node->handle_frame(packet.data, packet.status.rssi, packet.status.snr);
  });

  // start listening
  std::error_code ec;
  if (!radio->start_receive(ec)) {
    logger.error("Failed to start receiving: {}", ec.message());
    return;
  }
  logger.info("Node {} listening for Meshtastic traffic", node->node_id());

  // announce ourselves so we appear in other nodes' node lists
  node->send_node_info();

Note

This is an independent, clean-room implementation of the published Meshtastic protocol; it is not affiliated with or endorsed by Meshtastic LLC. “Meshtastic” is a registered trademark of Meshtastic LLC. See the component README for details.

Note

Scope: this implements the public default channel with PSK encryption. It does not implement PKI-encrypted direct messages, MQTT, store-and-forward, or the admin protocol.

Public Types

typedef std::function<bool(std::span<const uint8_t> frame)> transmit_fn

Function used to transmit a framed packet over the radio. Return true on success.

typedef std::function<void(const std::string &text, const meshtastic::PacketMetadata &metadata)> text_callback_fn

Callback invoked when a text message is received.

Param text:

The message text

Param metadata:

The packet metadata (sender, RSSI, SNR, …)

typedef std::function<void(const meshtastic::User &user, const meshtastic::PacketMetadata &metadata)> nodeinfo_callback_fn

Callback invoked when node info (a User message) is received.

typedef std::function<void(const meshtastic::Position &position, const meshtastic::PacketMetadata &metadata)> position_callback_fn

Callback invoked when a position is received.

typedef std::function<void(const meshtastic::DataMessage &data, const meshtastic::PacketMetadata &metadata)> data_callback_fn

Callback invoked for any received Data message (after decryption and decode), for handling port numbers not covered by the specific callbacks above.

Public Functions

explicit MeshtasticNode(const Config &config)

Constructor

Parameters:

config – The configuration for the node

inline const meshtastic::ModemConfig &modem_config() const

Get the LoRa modem configuration to apply to the radio for the configured region / preset / channel (frequency, bandwidth, spreading factor, coding rate, sync word).

Returns:

The modem configuration

inline uint32_t node_num() const

Get this node’s number.

Returns:

The node number

std::string node_id() const

Get this node’s id string (e.g. “!a1b2c3d4”).

Returns:

The node id string

bool send_text(std::string_view text, uint32_t destination = meshtastic::BROADCAST_ADDR, bool want_ack = false)

Send a text message on the channel.

Parameters:
  • text – The message text (UTF-8, up to ~200 bytes)

  • destination – The destination node, or BROADCAST_ADDR (default) to broadcast to the channel

  • want_ack – Whether to request an acknowledgement

Returns:

True if the message was transmitted

bool send_node_info()

Broadcast this node’s info (User message). Stock devices need this to show your node’s name in their node lists.

Returns:

True if the node info was transmitted

bool send_position(const meshtastic::Position &position)

Broadcast a position.

Parameters:

position – The position to broadcast

Returns:

True if the position was transmitted

bool send_data(const meshtastic::DataMessage &data, uint32_t destination = meshtastic::BROADCAST_ADDR, bool want_ack = false)

Send an arbitrary Data message on the channel (advanced use).

Parameters:
  • data – The Data message to send

  • destination – The destination node, or BROADCAST_ADDR to broadcast

  • want_ack – Whether to request an acknowledgement

Returns:

True if the message was transmitted

bool handle_frame(std::span<const uint8_t> frame, float rssi = 0, float snr = 0)

Handle a raw frame received from the radio. Decrypts, decodes, performs deduplication, dispatches callbacks, and (if configured) rebroadcasts.

Parameters:
  • frame – The raw received frame (header + encrypted payload)

  • rssi – The receive RSSI in dBm

  • snr – The receive SNR in dB

Returns:

True if the frame was a valid, newly-seen packet for our channel

void set_text_callback(const text_callback_fn &callback)

Set the callback invoked when a text message is received.

Parameters:

callback – The callback

void set_nodeinfo_callback(const nodeinfo_callback_fn &callback)

Set the callback invoked when node info is received.

Parameters:

callback – The callback

void set_position_callback(const position_callback_fn &callback)

Set the callback invoked when a position is received.

Parameters:

callback – The callback

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns:

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters:

tag – The tag to use for the logger

inline espp::Logger::Verbosity get_log_level() const

Get the log level for the logger

Returns:

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters:

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters:

level – The verbosity level to use for the logger

inline espp::Logger::Verbosity get_log_verbosity() const

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns:

The verbosity level of the logger

inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters:

rate_limit – The rate limit to use for the logger

struct Config

Configuration for the Meshtastic node.

Public Members

uint32_t node_num = {0}

This node’s number. If 0, a stable pseudo-random number is derived from the ESP32’s MAC address.

std::string long_name = {"espp node"}

This node’s long name.

std::string short_name = {"espp"}

This node’s short name (<= 4 chars)

meshtastic::HardwareModel hw_model = {meshtastic::HardwareModel::PRIVATE_HW}

This node’s hardware model.

meshtastic::Region region = {meshtastic::Region::US}

Regulatory region.

meshtastic::ModemPreset preset = {meshtastic::ModemPreset::LONG_FAST}

Modem preset.

std::string channel_name = {}

Channel name; empty uses the default channel (the preset’s display name)

std::vector<uint8_t> psk = {1}

The channel PSK. Default {1} = the public default key. See meshtastic::expand_psk.

transmit_fn transmit

Function used to transmit frames.

uint8_t hop_limit = {3}

Hop limit for originated broadcasts (0-7)

bool rebroadcast = {false}

Whether to rebroadcast (relay) others’ packets (managed flood). False = receive/originate only, which still fully interoperates.

text_callback_fn on_text = {nullptr}

Called on received text messages.

nodeinfo_callback_fn on_nodeinfo = {nullptr}

Called on received node info.

position_callback_fn on_position = {nullptr}

Called on received positions.

data_callback_fn on_data = {nullptr}

Called on any received Data message.

Logger::Verbosity log_level = {Logger::Verbosity::WARN}

Log verbosity.

Header File

Header File

Header File

Header File