Fanout
MQTT, bots, webhooks, Apprise, SQS — whatever Meshloom hears can leave again.
Fanout redistributes mesh events to other systems: private MQTT, community MQTT, bots, webhooks, Apprise, SQS, and map uploads. Configurations live in fanout_configs. Meshloom Community is a separate join state, not a Fanout row.
| Method | Endpoint | Effect |
|---|---|---|
| GET | /api/fanout |
List configurations |
| POST | /api/fanout |
Create one |
| PATCH | /api/fanout/{id} |
Update and reload the module |
| DELETE | /api/fanout/{id} |
Delete and stop the module |
Disabled configurations are drafts. GET /api/health reports connected, disconnected, or error.
Module types
| Type | What it does |
|---|---|
mqtt_private |
Publishes to your MQTT broker |
mqtt_community |
Publishes raw packets to a community broker |
bot |
Runs Python in response to messages |
webhook |
HTTP POST / PUT / PATCH with optional HMAC-SHA256 |
apprise |
Sends through Apprise URLs |
sqs |
Sends JSON envelopes to Amazon SQS |
map_upload |
Sends heard repeater and room adverts to map.meshcore.io |
Home Assistant MQTT Discovery has its own page: Home Assistant.
Scope
{"messages": "all", "raw_packets": "all"}
{"messages": "none", "raw_packets": "all"}
{"messages": {"channels": ["key1"], "contacts": "all"}, "raw_packets": "none"}
Scope filters decoded messages and raw packets. Contacts, repeater telemetry, and radio health go to every module; each module filters internally. Community MQTT and map_upload are locked to raw packets only. Historical decryption never replays fanout events.
Modules may receive messages (PRIV or CHAN, conversation key, text, sender, ACK state, paths, timestamps), raw packets (id, observation_id, hex payload, timestamp, optional decrypted_info), contacts, telemetry, and 60-second radio health snapshots. For raw packets, id is storage identity and may repeat; observation_id is unique per RF arrival.
Bots
Bots run Python entered in the UI through exec() with full __builtins__. Anyone who can reach the UI can execute arbitrary code on the host. See Security and A trusted network.
def bot(sender_name, sender_key, message_text, is_dm,
channel_key, channel_name, sender_timestamp, path):
if "!echo" in message_text.lower():
return f"[ECHO] {message_text}"
return None
Optional keyword arguments include region, scoped, is_outgoing, path_bytes_per_hop, and packet_hash. A bot may return None, a string, a list of strings, or {"region": ..., "message": ...}. Region scope applies only to channel replies. Bot execution has thread, timeout, concurrency, and rate limits.
MESHCORE_DISABLE_BOTS=true disables the system at startup and returns 403 for bot configuration changes. POST /api/fanout/bots/disable-until-restart stops bot modules until process restart.
Community MQTT
It publishes raw packets only. A direct packet’s optional path is a comma-separated list of hop identifiers, with widths of 1, 2, or 3 bytes according to path_hash_mode; it is not a byte-by-byte rendering.
Webhooks
hmac_secret adds an HMAC-SHA256 signature of the JSON body. The header is configured by hmac_header, defaulting to X-Webhook-Signature, and the value is sha256=<hex>.