Skip to content

Latest commit

 

History

History
444 lines (324 loc) · 13.9 KB

File metadata and controls

444 lines (324 loc) · 13.9 KB

Configuration Guide

Complete configuration reference for the Meshtastic MQTT Proxy.

Interface Configuration

TCP Interface

Connect to a Meshtastic node via TCP network connection.

Use Cases:

  • MeshMonitor virtual node
  • Meshtastic devices with network connectivity
  • Remote node access

Configuration:

INTERFACE_TYPE=tcp
TCP_NODE_HOST=192.168.1.100
TCP_NODE_PORT=4403
TCP_TIMEOUT=300

Parameters:

  • TCP_NODE_HOST - Hostname or IP address of the Meshtastic node
  • TCP_NODE_PORT - TCP port (default: 4403, MeshMonitor virtual node: 4404)
  • TCP_TIMEOUT - Connection timeout in seconds (default: 300)

Serial Interface

Connect to a USB-connected Meshtastic device.

Use Cases:

  • Direct USB connection to Meshtastic device
  • Raspberry Pi with USB radio
  • Development and testing

Configuration:

INTERFACE_TYPE=serial
SERIAL_PORT=/dev/ttyACM0

Parameters:

  • SERIAL_PORT - Device path (Linux: /dev/ttyACM0, /dev/ttyUSB0)

Finding Your Serial Port:

# List all serial devices
ls /dev/tty*

# Or use dmesg to see recent connections
dmesg | grep tty

Docker Requirements:

  • Device must be mapped in docker-compose.yml
  • Privileged mode required (already configured)

BLE Interface

Status: Not yet supported (code present but commented out)

BLE support requires custom implementation using the bleak library. See the meshtastic-ble-bridge project for reference.

Environment Variables

Core Settings

Variable Type Default Description
INTERFACE_TYPE string tcp Interface type: tcp or serial
LOG_LEVEL string INFO Logging level: DEBUG, INFO, WARNING, ERROR

TCP Settings

Variable Type Default Description
TCP_NODE_HOST string localhost TCP hostname or IP address
TCP_NODE_PORT integer 4403 TCP port number
TCP_TIMEOUT integer 300 Connection timeout (seconds)

Serial Settings

Variable Type Default Description
SERIAL_PORT string /dev/ttyUSB0 Serial device path

Advanced Settings

Variable Type Default Description
CONFIG_WAIT_TIMEOUT integer 60 Max time to wait for node config (seconds)
POLL_INTERVAL integer 1 Config polling interval (seconds)
EXTRA_MQTT_ROOTS string "" Comma-separated list of roots with optional prefixes for Virtual Channels (e.g. msh/US/OH:OH, msh/US/CA:CA)
MESH_ALLOW_UNCONFIGURED_CHANNELS boolean true Forward MQTT messages to the radio even if their channel is not explicitly configured on the physical node (Virtual Channel Passthrough). Set to false for strict filtering.

Health Check Settings

Variable Type Default Description
HEALTH_CHECK_ACTIVITY_TIMEOUT integer 300 Silence Threshold: Time without Radio activity before probing starts (seconds). Recommended 60.
HEALTH_CHECK_STATUS_INTERVAL integer 60 How often to log status information (seconds)
MQTT_RECONNECT_DELAY integer 5 Delay before attempting MQTT reconnection (seconds)

Message Queue Settings

Variable Type Default Description
MESH_TRANSMIT_DELAY float 0.5 Rate Limiting: Delay between outgoing packets (seconds). Prevents radio congestion.
MESH_MAX_QUEUE_SIZE integer 5000 Maximum number of outgoing messages buffered in RAM. A large queue handles sudden bursts without dropping messages. When full, the proxy uses a drop-oldest eviction strategy to ensure the newest messages reach the radio. Memory impact is negligible (~2.5MB per 10,000 messages).

Important

New "Probe & Kill" Logic:

  1. Silence Watchdog: If no data is received from the Radio for HEALTH_CHECK_ACTIVITY_TIMEOUT (default 300s, recommended 60s):

    • The proxy enters Probe Mode and sends a sendPosition command.
    • If no response is received within 30 seconds of the probe, the proxy will exit immediately (sys.exit(1)), triggering a Docker restart.
  2. Connection Lost Watchdog:

    • If the Meshtastic library reports a "Connection Lost" event (e.g., DNS resolution failure [Errno -2]), the proxy starts a 60-second timer.
    • If the connection is not re-established within that 60 seconds, the proxy will exit immediately to force a restart.

Extra MQTT Roots (Virtual Channels)

Monitor encrypted traffic from additional MQTT servers or root topics beyond your primary node configuration without causing RF crosstalk.

Configuration:

# Format: <root>:<alias>, ...
# The alias becomes the channel prefix in MeshMonitor (e.g. NC-LongFast)
EXTRA_MQTT_ROOTS=msh/US/NC:NC, msh/US/OH:Ohio

When configured, the proxy subscribes to {root}/2/e/# for each extra root in addition to your node's primary root.

How Virtual Channels Work:

When a packet arrives from an extra root, the proxy performs a two-part rewrite before injecting it into the radio:

  1. Topic rewrite: The MQTT topic channel name is prefixed with the alias.

    • msh/US/NC/2/e/LongFast/!abc123msh/US/2/e/NC-LongFast/!abc123
  2. Payload mutation (crosstalk prevention): The proxy mutates the packet.channel field inside the ServiceEnvelope protobuf.

    • packet.channel integer (PSK hash) → a synthetic hash derived from the virtual channel name

    The radio firmware uses this PSK hash to look up its decryption key. Since no local channel has the synthetic hash configured, the radio cannot decrypt the packet and will not rebroadcast it over RF — completely preventing cross-region crosstalk.

MeshMonitor Channel Database Setup:

Because the proxy preserves the original channel_id string and leaves the encrypted payload bytes untouched, MeshMonitor natively receives the exact original packet data.

You just need to ensure the original channel name and PSK exist in your MeshMonitor Channel Database. You do not need to create special NC- prefixed names.

Caution

Known Limitation (Shared Keys): If you use the same key for multiple channels (e.g., both your local LongFast and the virtual LongFast use AQ==), MeshMonitor will decode traffic for both into the exact same channel display.

You cannot turn on "Enforce Channel Name Validation" in MeshMonitor to separate them. Because the proxy must fake the PSK hash to prevent the physical radio from transmitting the packet, MeshMonitor's strict "Enforce Name" validation will fail the hash check and refuse to decrypt entirely.

As a result, virtual channel traffic will simply be merged into your existing local channel display if they share a key. Monitoring only: Virtual Channels are strictly read-only. Because the hardware radio does not know about virtual channels, there is no way to send a reply on a virtual channel. This is by design — the feature is intended for safe, passive cross-region monitoring without bridging two networks.

Important

Loop Prevention: When MeshMonitor echoes a virtual channel packet back to the proxy, the proxy's uplink filter automatically drops it (since the virtual channel is not defined on the physical radio). This prevents an infinite proxy → MeshMonitor → MQTT → proxy feedback loop.

Meshtastic Node Configuration

The Meshtastic node must have MQTT properly configured for the proxy to work.

Required Settings

Check your node configuration:

meshtastic --get mqtt

Required values:

mqtt.enabled: True
mqtt.proxy_to_client_enabled: True
mqtt.address: <your-mqtt-broker>
mqtt.username: <mqtt-username>
mqtt.password: <mqtt-password>

Enabling MQTT Proxy

If not enabled, configure your node:

meshtastic --set mqtt.enabled true
meshtastic --set mqtt.proxy_to_client_enabled true
meshtastic --set mqtt.address mqtt.example.com
meshtastic --set mqtt.username myuser
meshtastic --set mqtt.password mypass

Caution

Why proxy_to_client_enabled Matters: When the firmware has proxy_to_client_enabled turned on, it fundamentally changes how it confirms message delivery. It stops generating "Implicit ACKs" automatically. Instead, it relies on the MQTT Broker echoing the message back to the Proxy. If the Proxy fails to forward this echo (as was a bug in previous versions), the firmware will hit a MAX_RETRANSMIT timeout (approx 45 seconds). In MeshMonitor, this results in a "Red X" (Failed delivery status) for Channel Broadcasts, even if the payload successfully reached the broker!

Channel Configuration (Uplink/Downlink Filtering)

The proxy automatically respects your node's channel settings for MQTT filtering. You do not need to configure these in the proxy itself; it reads them directly from the connected Meshtastic device.

For each configured channel on your node:

  • If uplink_enabled is false, the proxy will drop messages received from the mesh on that channel instead of sending them to the MQTT broker.
  • If downlink_enabled is false, the proxy will ignore messages received from the MQTT broker destined for that channel instead of transmitting them to the mesh.

You can configure these settings using the Meshtastic CLI:

meshtastic --ch-index 0 --set uplink_enabled false
meshtastic --ch-index 0 --set downlink_enabled false

Docker Compose Configuration

Basic Setup

services:
  mqtt-proxy:
    build: .
    image: mqtt-proxy
    container_name: mqtt-proxy
    restart: unless-stopped
    environment:
      - INTERFACE_TYPE=${INTERFACE_TYPE:-tcp}
      - TCP_NODE_HOST=${TCP_NODE_HOST:-localhost}
      - TCP_NODE_PORT=${TCP_NODE_PORT:-4403}
    network_mode: host

Serial Interface Setup

For serial connections, add device mapping:

services:
  mqtt-proxy:
    # ... other config ...
    devices:
      - /dev/ttyACM0:/dev/ttyACM0
    privileged: true

Example Configurations

MeshMonitor Virtual Node

INTERFACE_TYPE=tcp
TCP_NODE_HOST=192.168.1.100
TCP_NODE_PORT=4404
LOG_LEVEL=INFO

USB-Connected Device

INTERFACE_TYPE=serial
SERIAL_PORT=/dev/ttyACM0
LOG_LEVEL=INFO

Development/Debug

INTERFACE_TYPE=tcp
TCP_NODE_HOST=localhost
TCP_NODE_PORT=4403
LOG_LEVEL=DEBUG
CONFIG_WAIT_TIMEOUT=120

Logging

Log Levels

  • DEBUG - Detailed debugging information (verbose)
  • INFO - General informational messages (default)
  • WARNING - Warning messages
  • ERROR - Error messages only

Viewing Logs

# Follow logs in real-time
docker compose logs -f mqtt-proxy

# View last 100 lines
docker compose logs --tail=100 mqtt-proxy

# View logs since 10 minutes ago
docker compose logs --since=10m mqtt-proxy

Log Output Examples

Successful Connection:

[INFO] MQTT Proxy starting (interface: TCP)...
[INFO] Creating TCP interface...
[INFO] Connected to node !10ae8907
[INFO] Starting MQTT Client...
[INFO] MQTT Connected with result code: 0

MQTT Traffic:

[INFO] MQTT RX (Forwarding): Topic=msh/US/2/e/LongFast/!12345678 Size=156 bytes
[INFO] Node→MQTT: Topic=msh/US/2/e/LongFast/!87654321 Size=142 bytes

Troubleshooting

Common Issues

"No localNode available"

  • Node not responding
  • Check connection settings
  • Verify node is powered on

"MQTT is NOT enabled in node config"

  • Enable MQTT on node: meshtastic --set mqtt.enabled true
  • Enable proxy mode: meshtastic --set mqtt.proxy_to_client_enabled true

"Connection timeout"

  • Increase TCP_TIMEOUT
  • Check network connectivity
  • Verify firewall rules

Serial device not found

  • Check device path: ls /dev/tty*
  • Verify device permissions
  • Ensure device is mapped in docker-compose.yml

Health Check Issues

Container keeps restarting

  • Check logs: docker compose logs --tail=100 mqtt-proxy
  • Look for "Health check FAILED" messages
  • Common causes:
    • MQTT broker is down or unreachable
    • No message activity for > 5 minutes (configurable via HEALTH_CHECK_ACTIVITY_TIMEOUT)
    • Meshtastic node disconnected

Monitoring container health

# Check current health status
docker inspect --format='{{.State.Health.Status}}' mqtt-proxy

# View health check logs
docker inspect --format='{{range .State.Health.Log}}{{.Output}}{{end}}' mqtt-proxy

Understanding health check failures The health check monitors:

  1. MQTT connection state (must be connected)
  2. Message activity (must send or receive within timeout period)

Status logs appear every 60 seconds showing:

  • MQTT connection state
  • Message TX/RX counts and last activity time
  • Warnings when approaching activity timeout

Performance Tuning

Timeout Settings

Adjust timeouts based on your network:

# Slow/unreliable network
TCP_TIMEOUT=600
CONFIG_WAIT_TIMEOUT=120

# Fast/reliable network
TCP_TIMEOUT=60
CONFIG_WAIT_TIMEOUT=30

Polling Interval

Adjust config polling frequency:

# More responsive (higher CPU)
POLL_INTERVAL=0.5

# Less responsive (lower CPU)
POLL_INTERVAL=2

Security Considerations

Network Security

  • Use firewall rules to restrict TCP access
  • Consider VPN for remote connections
  • Use strong MQTT credentials

Docker Security

  • Run with minimal privileges when possible
  • Keep Docker images updated
  • Review docker-compose.yml security settings

Advanced Topics

Multiple Proxies

Run multiple proxy instances for different nodes:

services:
  mqtt-proxy-1:
    # ... config for node 1 ...
    
  mqtt-proxy-2:
    # ... config for node 2 ...

Custom Docker Network

Use bridge network instead of host mode:

services:
  mqtt-proxy:
    # ... other config ...
    networks:
      - mqtt-network
    ports:
      - "4403:4403"

networks:
  mqtt-network:
    driver: bridge

For more information, see README.md or open an issue on GitHub.