Meshtastic

From RevSpace
Jump to navigation Jump to search
Project Meshtastic
Experiments with Meshtastic
Status In progress
Contact bertrik
Last Update 2025-03-13

1. Intro

The plan is to use Meshtastic to transfer citizen science measurement data.

Stuff to figure out:

  • network coverage: meshnet.nl map
  • do nodes forward packets that do not belong to their "own" network? -> appears to be so!

My node: https://db.meshnet.nl/da639b54.html

Done:

  • I know the basics of meshtastic
  • Understand how the encryption works, how keys are constructed, how nonce/salt is constructed
  • Can pick up messages sent through the network and shared via MQTT back into a local application and decrypt them

TODO

  • create a particulate matter sensor that sends meshtastic
    • figure out the LoRa settings for a LoRa transceiver
    • actually build it and test it out
  • write a backend/plugin for my sensor-data-bridge

2. Design

Overall design:

  • citizen science nodes send data in meshtastic-compatible format, so packets can be routed accross the meshtastic network
  • data is sent from the node typically every 5 minutes
  • data is broadcasted inside the network, until it reaches a node with a MQTT backend connection, typically within a maximum of 3 hops.
  • data arriving at the MQTT server is picked up by a backend application, which can then process it further
  • we use a more-or-less citizen-science-data specific channel, so we don't interfere with other meshtastic traffic

Protocol design:

  • Use a dedicated channel (longfast? + custom key)
  • Use standard network concepts from meshtastic as much as possible to comply with meshtastic expectations for smooth operation
  • Instead of the MeshPacket structure, we directly use the citizen science payload, so no wrapping in a protobuf with portnr + payload
  • Citizen science payload has its own custom encoding
  • A checksum (16-bit/32-bit?) at the end of the payload allows us to verify that it really is a citizen science data packet after decryption -> do we really need this if we already have a channel?
  • Each packet already has a semi-unique packet id, so we can identify duplicates at the backend

Backend:

  • The backend application listens on a topic on the de-facto central MQTT server for the netherlands, used by most meshtastic nodes, which is mqtt.meshnet.nl
  • Decoding works as follows:
    • Decrypt with the pre-shared-key (this always work but might result in garbage)
    • Attempt to decode according to the the protobuf portnum+payload (meshtastic 'Data')
    • Check the port number
    • Check and remove the 16-bit checksum in the payload
  • If all of the steps above check out, consider it to be a valid packet
  • Check in a local cache if this is a duplicate packet and if so, ignore it
  • process citizen science data payload: there is no such thing as TTN attributes, so any data required for further forwarding need to be kept locally (e.g. login credentials for opensense / sensor.community)

2.1. Packet structure

On the radio level:

[ lora preamble | ... | <payload> ] <to be documented>

Within the radio payload:

[ meshtastic 16-byte header | citizen science payload | CRC ]
                            |<--meshtastic encrypted part-->]

Within the protobuf payload, data encoded according to custom encoding (e.g. packed binary)

[citizen science data | 16-bit CRC]

3. Protocol

See https://meshtastic.org/docs/overview/mesh-algo/

Quick links:

4. Hardware

Nice antenna? https://nl.aliexpress.com/item/1005007301116616.html

5. MQTT

In the netherlands, data is typically sent to the 'boreft' MQTT server, for example

 mosquitto_sub -h mqtt.meshnet.nl -u boreft -P meshboreft -t "#" -v

Examples of typical data:

 msh/7460-7463/2/stat/!da5857c0 online
 msh/EU_868/NL/2/e/LongFast/!eb66115c �%]�g(=���gx�� H5��Aw=]�gE��H`���������LongFast␦

5.1. Example data

Examples of data as decoded from MQTT using the meshtastic python service wrapper:

packet {
  from: 2732702784
  to: 4294967295
  decoded {
    portnum: POSITION_APP
    payload: "\r\224\234\024\037\025\303\266\233\002\030\n\270\001 "
  }
  id: 663882246
  rx_time: 1741511999
  rx_snr: -18
  hop_limit: 2
  rx_rssi: -128
  hop_start: 3
}
channel_id: "LongFast"
gateway_id: "!da544e50"

Packet with encrypted data:

packet {
  from: 1128181476
  to: 4294967295
  channel: 8
  encrypted: "\007\355{o\340e\352\221\204\3112\365h\304[0\321&\351^{]\264\334\373\320\313>\213\2635\023\345'"
  id: 4272151039
  rx_time: 1741512321
  rx_snr: 5.75
  hop_limit: 4
  rx_rssi: -83
  hop_start: 5
}
channel_id: "LongFast"
gateway_id: "!da5c87d4"