mirror of
https://github.com/dpup/meshstream.git
synced 2026-07-05 17:31:06 +02:00
Update decoder to match correct Meshtastic MQTT topic structure
This commit is contained in:
@@ -1 +1,52 @@
|
||||
- Never run the program, you may build it and run tests, but I will run the program manually.
|
||||
# Meshtastic MQTT Protocol Structure
|
||||
|
||||
## Topic Structure
|
||||
|
||||
The Meshtastic MQTT topic structure follows this pattern:
|
||||
```
|
||||
msh/REGION/2/e/CHANNELNAME/USERID
|
||||
```
|
||||
|
||||
- `msh`: Fixed prefix for all Meshtastic topics
|
||||
- `REGION`: Geographic region code (e.g., `US`, `EU`, `AU`)
|
||||
- `2`: Protocol version
|
||||
- `e`: Encrypted channel indicator (versions before 2.3.0 used `/c/` instead)
|
||||
- `CHANNELNAME`: The channel name used in the Meshtastic network
|
||||
- `USERID`: Unique identifier for the device, formats include:
|
||||
- `!` followed by hex characters for MAC address based IDs
|
||||
- `+` followed by phone number for Signal-based IDs
|
||||
|
||||
## Message Types
|
||||
|
||||
### Protobuf Messages (Binary)
|
||||
Topic pattern: `msh/REGION/2/e/CHANNELNAME/USERID`
|
||||
- Raw MeshPacket transmissions in protobuf format
|
||||
- Can be encrypted or unencrypted based on channel settings
|
||||
|
||||
### JSON Messages
|
||||
Topic pattern: `msh/REGION/2/json/CHANNELNAME/USERID`
|
||||
- Structured JSON payloads with fields like:
|
||||
- `id`: Message ID
|
||||
- `from`: Node ID of sender
|
||||
- `to`: Node ID of recipient (or blank for broadcast)
|
||||
- `payload`: The actual message content
|
||||
- `timestamp`: Time the message was received
|
||||
|
||||
Note: JSON format is not supported on nRF52 platform devices.
|
||||
|
||||
### Special Topics
|
||||
- MQTT Downlink: `msh/REGION/2/json/mqtt/`
|
||||
- Used for sending instructions to gateway nodes
|
||||
|
||||
## Important Notes
|
||||
|
||||
- The public MQTT server implements a zero-hop policy (only direct messages)
|
||||
- JSON messages may include specific data types like:
|
||||
- NodeInfo
|
||||
- Telemetry
|
||||
- Text Messages
|
||||
- Position Updates
|
||||
- Position data on public servers has reduced precision for privacy
|
||||
- Binary messages use the protocol buffers format defined in the Meshtastic codebase
|
||||
|
||||
This corrects the previous assumption that the topic structure was `msh/REGION/STATE/NAME`, which was incorrect.
|
||||
+38
-21
@@ -19,7 +19,9 @@ const (
|
||||
// DecodedPacket contains information about a decoded packet
|
||||
type DecodedPacket struct {
|
||||
Topic string
|
||||
Region string
|
||||
Channel string
|
||||
UserID string
|
||||
Type PacketType
|
||||
JSONData map[string]interface{}
|
||||
FromNode string
|
||||
@@ -38,20 +40,40 @@ func DecodePacket(topic string, payload []byte) (*DecodedPacket, error) {
|
||||
}
|
||||
|
||||
// Extract channel and other info from topic
|
||||
// Format: msh/REGION/2/e/CHANNELNAME/USERID
|
||||
// or: msh/REGION/2/json/CHANNELNAME/USERID
|
||||
parts := strings.Split(topic, "/")
|
||||
if len(parts) < 4 {
|
||||
return packet, fmt.Errorf("invalid topic format: %s", topic)
|
||||
}
|
||||
|
||||
// Set channel info (typically msh/REGION/STATE/NAME)
|
||||
packet.Channel = strings.Join(parts[1:4], "/")
|
||||
// Set the region
|
||||
if len(parts) >= 2 {
|
||||
packet.Region = parts[1]
|
||||
}
|
||||
|
||||
// Try to determine type from topic structure
|
||||
// Extract channel name - should be part 4 for binary or part 5 for JSON
|
||||
if len(parts) >= 5 {
|
||||
typeIndicator := parts[4]
|
||||
|
||||
switch typeIndicator {
|
||||
case "json":
|
||||
if parts[3] == "e" || parts[3] == "c" {
|
||||
// Binary format: msh/REGION/2/e/CHANNELNAME/USERID
|
||||
if len(parts) >= 5 {
|
||||
packet.Channel = parts[4]
|
||||
}
|
||||
if len(parts) >= 6 {
|
||||
packet.UserID = parts[5]
|
||||
}
|
||||
// This is a binary protobuf packet
|
||||
packet.Type = TypeBinary
|
||||
} else if parts[3] == "json" {
|
||||
// JSON format: msh/REGION/2/json/CHANNELNAME/USERID
|
||||
if len(parts) >= 5 {
|
||||
packet.Channel = parts[4]
|
||||
}
|
||||
if len(parts) >= 6 {
|
||||
packet.UserID = parts[5]
|
||||
}
|
||||
|
||||
// This is a JSON packet
|
||||
packet.Type = TypeJSON
|
||||
if err := json.Unmarshal(payload, &packet.JSONData); err != nil {
|
||||
return packet, fmt.Errorf("failed to parse JSON: %v", err)
|
||||
@@ -70,19 +92,8 @@ func DecodePacket(topic string, payload []byte) (*DecodedPacket, error) {
|
||||
if ts, ok := packet.JSONData["timestamp"].(string); ok {
|
||||
packet.Timestamp = ts
|
||||
}
|
||||
|
||||
case "binary":
|
||||
// Binary protobuf payload
|
||||
packet.Type = TypeBinary
|
||||
// Note: Actual protobuf decoding would be done here
|
||||
|
||||
case "text":
|
||||
// Plain text payload
|
||||
packet.Type = TypeText
|
||||
packet.Text = string(payload)
|
||||
|
||||
default:
|
||||
// Try to infer type from payload
|
||||
} else {
|
||||
// Unknown format, try to infer from content
|
||||
if len(payload) > 0 && payload[0] == '{' {
|
||||
// Looks like JSON
|
||||
packet.Type = TypeJSON
|
||||
@@ -113,7 +124,7 @@ func DecodePacket(topic string, payload []byte) (*DecodedPacket, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return packet, nil
|
||||
}
|
||||
|
||||
@@ -139,7 +150,13 @@ func FormatPacket(packet *DecodedPacket) string {
|
||||
var builder strings.Builder
|
||||
|
||||
builder.WriteString(fmt.Sprintf("Topic: %s\n", packet.Topic))
|
||||
|
||||
// Show basic topic structure
|
||||
builder.WriteString(fmt.Sprintf("Region: %s\n", packet.Region))
|
||||
builder.WriteString(fmt.Sprintf("Channel: %s\n", packet.Channel))
|
||||
if packet.UserID != "" {
|
||||
builder.WriteString(fmt.Sprintf("User ID: %s\n", packet.UserID))
|
||||
}
|
||||
|
||||
switch packet.Type {
|
||||
case TypeJSON:
|
||||
|
||||
@@ -67,7 +67,10 @@ func main() {
|
||||
log.Fatalf("Error connecting to MQTT broker: %v", token.Error())
|
||||
}
|
||||
|
||||
// Subscribe to topic
|
||||
// Subscribe to all topics for this region
|
||||
// This will capture:
|
||||
// - msh/US/CA/Motherlode/2/e/# (binary protobuf data)
|
||||
// - msh/US/CA/Motherlode/2/json/# (JSON formatted data)
|
||||
topic := mqttTopicPrefix + "/#"
|
||||
token := client.Subscribe(topic, 0, nil)
|
||||
token.Wait()
|
||||
|
||||
Reference in New Issue
Block a user