# Meshtastic Demodulator JSON UDP Packet Format

## Conditions

    Condition                    lora.packet_type   meshtastic section
    ---------------------------  -----------------  --------------------------------------------------
    Meshtastic, decrypted        meshtastic         present, decryption: decrypted, parsed: true, full fields
    Meshtastic, plaintext        meshtastic         present, decryption: plaintext, parsed: true, full fields
    Meshtastic, not decrypted    meshtastic         present, decryption: not_decrypted, parsed: false, no fields
    LoRaWAN                      lorawan            absent
    Helium                       helium             absent
    Unknown/unset                unset              absent
    Other private network        custom             absent


## Fields Always Present

    timestamp           Local ISO 8601, no timezone, e.g. 2026-04-24T18:40:25.123
    timestamp_unix      Milliseconds since Unix epoch
    rf.center_freq_hz   Device center frequency plus channel offset in Hz
    rf.bandwidth_hz     LoRa bandwidth in Hz
    rf.spreading_factor LoRa spreading factor integer
    rf.signal_db        Signal power in dB
    rf.noise_db         Noise floor in dB
    rf.snr_db           Signal minus noise in dB
    lora.packet_type    meshtastic, lorawan, helium, unset, or custom
    lora.sync_word      Hex string e.g. 0x2b
    lora.header_fec     ok, fix, err, or n/a
    lora.header_crc     ok or err
    lora.payload_fec    ok, fix, err, or n/a (n/a when early_eom is true)
    lora.payload_crc    ok, err, or n/a (n/a when early_eom is true)
    lora.early_eom      true or false
    lora.packet_length  Payload length in bytes
    lora.nb_symbols     Symbol count integer
    lora.nb_codewords   Codeword count integer
    lora.payload_hex    Raw payload as continuous lowercase hex string


## Fields Present Only When lora.packet_type Is meshtastic

    meshtastic.channel_hash        Hex string e.g. 0x08
    meshtastic.packet_id           Meshtastic 32-bit unique packet ID hex string e.g. 0x5a42f351
    meshtastic.hash_matching_index Integer index of matched key, or none
    meshtastic.decryption          decrypted, plaintext, or not_decrypted
    meshtastic.key_label           Key name, no_key, or unknown_key
    meshtastic.parsed              true or false


## Fields Present Only When meshtastic.parsed Is true

    meshtastic.channel_type    Modem preset name e.g. LONG_FAST
    meshtastic.hop_start       Integer
    meshtastic.hop_limit       Integer
    meshtastic.hops_consumed   Integer, equals hop_start minus hop_limit
    meshtastic.relay_node      Integer node ID of last relay
    meshtastic.fields          Object containing all decoded fields as dot-path key/value pairs


## Decryption Values

    decrypted      Payload was successfully decrypted using a matching key
    plaintext      Payload parsed directly without encryption
    not_decrypted  All available keys were tried, none succeeded


## Key Label Values

    <name>         Actual key label e.g. LongFast:default
    no_key         Packet was plaintext, no key was used
    unknown_key    Decryption failed, key is unknown


## FEC and CRC Values

    ok    Check passed with no errors
    fix   Errors detected and corrected by FEC
    err   Errors detected but not correctable
    n/a   Not applicable, packet ended early before payload was received


## Note on packet_id

    The Meshtastic packet ID is a large random 32-bit value generated by the originating node.
    Its primary purpose is to serve as a cryptographic nonce component for AES-CTR decryption,
    combined with the from node ID. It also serves as a deduplication key in the mesh so that
    relay nodes can discard copies of already-forwarded packets. It is not a sequential counter.


## Example: Fully Decoded Meshtastic Packet

    {
      "timestamp": "2026-04-24T18:40:25.123",
      "timestamp_unix": 1745541625123,
      "rf": {
        "center_freq_hz": 906875000,
        "bandwidth_hz": 250000,
        "spreading_factor": 11,
        "signal_db": -46.0,
        "noise_db": -84.2,
        "snr_db": 13.6
      },
      "lora": {
        "packet_type": "meshtastic",
        "sync_word": "0x2b",
        "header_fec": "ok",
        "header_crc": "ok",
        "payload_fec": "ok",
        "payload_crc": "ok",
        "early_eom": false,
        "packet_length": 58,
        "nb_symbols": 152,
        "nb_codewords": 58,
        "payload_hex": "ffffffff363e0c47..."
      },
      "meshtastic": {
        "channel_hash": "0x08",
        "packet_id": "0x5a42f351",
        "hash_matching_index": 0,
        "decryption": "decrypted",
        "key_label": "LongFast:default",
        "parsed": true,
        "channel_type": "LONG_FAST",
        "hop_start": 3,
        "hop_limit": 1,
        "hops_consumed": 2,
        "relay_node": 165,
        "fields": {
          "header.to": "0xffffffff",
          "header.from": "0xc4a4bc28",
          "header.via_mqtt": "false",
          "data.port_name": "NODEINFO_APP",
          "nodeinfo.long_name": "us.tx.addison.001",
          "nodeinfo.short_name": "nvx2",
          "nodeinfo.macaddr": "c7:d4:17:07:43:8a",
          "nodeinfo.hw_model": "9",
          "nodeinfo.is_licensed": "true"
        }
      }
    }


## Example: Not Decrypted

    {
      "timestamp": "2026-04-24T18:40:25.123",
      "timestamp_unix": 1745541625123,
      "rf": { ... },
      "lora": {
        "packet_type": "meshtastic",
        "sync_word": "0x2b",
        ...
      },
      "meshtastic": {
        "channel_hash": "0x08",
        "packet_id": "unknown",
        "hash_matching_index": "none",
        "decryption": "not_decrypted",
        "key_label": "unknown_key",
        "parsed": false
      }
    }


## Example: LoRaWAN Packet

    {
      "timestamp": "2026-04-24T18:40:25.123",
      "timestamp_unix": 1745541625123,
      "rf": { ... },
      "lora": {
        "packet_type": "lorawan",
        "sync_word": "0x12",
        ...
        "payload_hex": "ffffffff363e0c47..."
      }
    }