Data Sources
Connect controls straight to protocols you already run — an MQTT broker or a plain HTTP API — with no MeshSocket bridge and zero server code. MeshSocket stays the power path (dynamic content, rooms, E2EE, readback); sources are the zero-setup path.
A layout declares named sources at the top level; controls bind them through the
same standardized connection block (Sync / Actions) they use for
MeshSocket. Every control's inputs and outputs are transport-independent: what a
Gauge accepts or a Button emits is defined by the control, and method
just picks the wire.
Definition
"sources": {
"broker": { "type": "mqtt", "url": "mqtt://192.168.1.10:1883",
"username": "ha", "password": "secret" },
"api": { "type": "http", "baseURL": "http://192.168.1.5:8080",
"headers": { "Authorization": "Bearer abc" }, "interval": 5 }
}
When a layout has exactly one source of a kind, sync/action entries may omit
source — it resolves automatically. With several, name the one you mean.
MQTT
Subscribe a topic and bind the payload — the entire connection block of the control is:
"sync": [{ "method": "mqtt", "topic": "home/livingroom/temp", "valuePath": "value" }]
- Topic wildcards work (
home/+/temp,sensors/#). - Payloads parse naturally: JSON objects work with
filter/valuePathexactly like MeshSocket frames; bare23.5/true/ONpayloads become number / bool / string values directly (leavevaluePathempty). - Actions publish:
"action": { "method": "mqtt", "topic": "home/lamp/set", "payload": "{{value}}", "retain": false }
String payloads publish raw bytes (ON, not "ON"); objects publish as JSON.
mqtt:// is plain TCP (default port 1883), mqtts:// is TLS (default 8883).
QoS 0 publish; inbound QoS 1 is acknowledged. The client auto-reconnects with
backoff and reports state to the connection console.
HTTP polling
Poll any JSON endpoint on an interval and extract a value:
"sync": [{ "method": "http", "path": "/api/status", "interval": 10, "valuePath": "cpu.load" }]
url(absolute) orpath(against the source'sbaseURL).- Controls polling the same URL at the same interval share one request — a page of gauges over one status endpoint costs one poll.
- The response body is JSON;
filterandvaluePathbehave exactly as in Sync. Special receivers work too: point a List at an array endpoint, a Sparkline at a numeric one. - Actions fire requests:
"action": { "method": "http", "path": "/api/restart", "httpMethod": "POST",
"payload": { "service": "media" } }
httpMethod defaults to POST when a payload is present, else GET. Object
payloads send as JSON bodies; string payloads send as text.
Full example — an ESP32 + Home Assistant page, no server
{
"name": "Greenhouse",
"version": 1,
"sources": { "broker": { "type": "mqtt", "url": "mqtt://192.168.1.10" } },
"tabs": [{
"title": "Climate", "icon": "leaf.fill", "grid": { "columns": 2, "rows": 6 },
"children": [
{ "type": "gauge", "id": "temp", "position": [0, 0], "min": 0, "max": 40,
"label": "Temp °C",
"sync": [{ "method": "mqtt", "topic": "greenhouse/temp" }] },
{ "type": "sparkline", "id": "hum", "position": [0, 1], "label": "Humidity",
"sync": [{ "method": "mqtt", "topic": "greenhouse/humidity" }] },
{ "type": "toggle", "id": "fan", "position": [2, 0], "label": "Fan",
"sync": [{ "method": "mqtt", "topic": "greenhouse/fan/state",
"valuePath": "" }],
"action": { "method": "mqtt", "topic": "greenhouse/fan/set",
"payload": "{{value}}" } }
]
}]
}
Mixing transports
A layout may use MeshSocket, MQTT, HTTP, and Sensors together — each sync
entry picks its own method. A control with several sync entries takes whichever
delivered last.
Notes
- Sources live and die with the layout: leaving it disconnects the broker and stops all polling.
- MQTT needs a declared source (the broker address); HTTP syncs with an absolute
urlwork with nosourcesblock at all. - Diagnostics (connects, failures, reconnects) land in the connection console like MeshSocket's.
Related
- Sync — the standardized inbound binding
- Actions — the standardized outbound command
- Layout Config — where
sourcessits