Configuration Reference
Overview
Siphon uses a strict, declarative YAML configuration.
Example config: mekops-labs/siphon/blob/main/configs/example.yaml
Env variables substitution
Whole configuration file is first parsed and all %%ENV_NAME%% references are
substituted by values of environmental variables seen by siphon.
The Global Block
The root of the document requires the V2 schema declaration.
1version: 2
Collectors
Collectors define how Siphon ingests data. Each collector is given a unique alias and maps raw input parameters to internal Event Bus topics.
mqtt
mekops-labs/siphon/blob/main/pkg/collector/mqtt/README.md
Used to subscribe to one or more topics on a remote or local MQTT broker.
Parameters (params):
url(required): The connection string (e.g., tcp://127.0.0.1:1883 or ssl://broker.example.com:8883).user: Username for authentication.pass: Password for authentication.
Topics (topics): A map where the key is the internal Siphon bus topic (alias) and the value is the actual MQTT topic string.
file
mekops-labs/siphon/blob/main/pkg/collector/file/README.md
Reads the content of local system files, typically used for monitoring hardware sensors or system metrics.
Parameters (params):
interval: Frequency of polling in seconds (default: 10).
Topics (topics): A map where the key is the internal bus topic and the value is the absolute path to the file.
shell
mekops-labs/siphon/blob/main/pkg/collector/shell/README.md
Executes an OS command periodically and captures its stdout.
Parameters (params):
interval: Frequency of execution in seconds (default: 10).
Topics (topics): A map where the key is the internal bus topic and the value is the shell command to run.
hass
mekops-labs/siphon/blob/main/pkg/collector/hass/README.md
A specialized collector for Home Assistant. It polls entity states via the REST API. When running as an official Add-on,
it automatically handles authentication using the $SUPERVISOR_TOKEN.
Parameters (params):
interval: Polling frequency in seconds (default: 30)
Topics (topics): A map where the key is the internal bus topic and the value is the Home Assistant entity ID (e.g.,
sensor.living_room_temp). Supports wildcard * value - in this case returns all the entities in JSON format.
rest
mekops-labs/siphon/blob/main/pkg/collector/rest/README.md
Polls a remote HTTP endpoint via GET request periodically and captures the response body.
Parameters (params):
interval: Frequency of polling in seconds (default: 10).
Topics (topics): A map where the key is the internal bus topic and the value is the full URL to poll.
1collectors:
2 weather:
3 type: rest
4 params:
5 interval: 60
6 topics:
7 current_weather: "https://wttr.in/?format=%C"
webhook
mekops-labs/siphon/blob/main/pkg/collector/webhook/README.md
Starts a high-performance, hardened HTTP listener that allows external systems (GitHub, Grafana, custom scripts) to push data directly into Siphon. The server is designed for public internet exposure with multi-layer defense against DDoS attacks, memory exhaustion, and unauthorized access.
Parameters (params):
port(required): The port to listen on.token: If set, rejects any request missing a matchingAuthorization: Bearer <token>header.rps: Sustained requests per second allowed by the rate limiter (default: unlimited).burst: Maximum concurrent burst of requests allowed (default: unlimited).max_body_mb: Hard limit on incoming payload size in megabytes (default: unlimited).dedupe_ttl: Duration in seconds during which identical payloads (by SHA-256 hash) are dropped to prevent duplicate pipeline processing. Returns409 Conflictto the sender so the caller can distinguish a processed request from a deduplicated one. Only authenticated callers can observe this response.
Topics (topics): A map where the key is the internal bus topic and the value is the HTTP path to expose.
1collectors:
2 secure_api:
3 type: webhook
4 params:
5 port: 8080
6 token: "%%MY_WEBHOOK_SECRET%%"
7 rps: 5.0
8 burst: 10
9 max_body_mb: 2
10 dedupe_ttl: 300
11 topics:
12 github_hooks: "/webhooks/github"
13 sensor_push: "/data/sensor01"
Best Practice: Siphon does not handle TLS natively. Place Siphon behind a reverse proxy (Nginx, Caddy, Traefik) to provide HTTPS encryption. Store secrets via
%%ENV_VAR%%substitution rather than hardcoding them.
Example collector definition
1collectors:
2 local_ha:
3 type: hass
4 params:
5 interval: 60
6 topics:
7 outdoor_temp: "sensor.backyard_temperature"
Sinks
Sinks define the egress points for your telemetry data. They are defined globally in the sinks block and can be
referenced by name within multiple pipelines.
bus
mekops-labs/siphon/blob/main/pkg/sink/bus/README.md
Publishes the processed payloads back to the internal bus.
Parameters (params):
topic(required): The internal bus topic to publish to.
gotify
mekops-labs/siphon/blob/main/pkg/sink/gotify/README.md
Sends push notifications to a Gotify server.
Parameters (params):
url(required): The base URL of your Gotify instance.token(required): The application token.title: The notification title. This fields uses template rendering.nowfunction is defined as alias to time.Now().Format() (default "Siphon Alert")priority: The notification priority (default 0)
ntfy
mekops-labs/siphon/blob/main/pkg/sink/ntfy/README.md
Sends notifications to ntfy.sh or a self-hosted instance.
Parameters (params):
url(required): The ntfy instance URL (e.g.,https://ntfy.sh).topic(required): The ntfy topictoken: The ntfy token (default: "")title: The notification title. This fields uses template rendering.nowfunction is defined as alias to time.Now().Format() (default: "")priority: The notification priority (default: 3)
windy
mekops-labs/siphon/blob/main/pkg/sink/windy/README.md
Updates a Personal Weather Station (PWS) on Windy.com.
Parameters (params):
id(required): Your Station ID.password(required): Your Windy PWS password from station's page.
iotplotter
mekops-labs/siphon/blob/main/pkg/sink/iotplotter/README.md
Dispatches data to the IoTPlotter service.
Parameters (params):
url: The API endpoint (default:http://iotplotter.com).apikey(required): Your account API key.feed(required): The specific feed ID to update.
stdout
mekops-labs/siphon/blob/main/pkg/sink/stdout/README.md
Prints the final payload to the Siphon logs. Useful for debugging.
Parameters (params):
- None.
mqtt
mekops-labs/siphon/blob/main/pkg/sink/mqtt/README.md
Publishes the final pipeline payload to a topic on an MQTT broker. Useful for sending processed data, aggregations, or alerts back to Home Assistant or other IoT dashboards.
Parameters (params):
url(required): The broker connection string (e.g.,tcp://192.168.1.100:1883).user: Username for authentication. Supports%%ENV_VAR%%substitution.pass: Password for authentication. Supports%%ENV_VAR%%substitution.topic(required): The MQTT topic to publish to.qos: Quality of Service level —0,1, or2(default:0).retained: Whether the broker should retain the message (default:false).
hass
mekops-labs/siphon/blob/main/pkg/sink/hass/README.md
Integrates with Home Assistant's MQTT Auto-Discovery feature. When Siphon starts, this sink automatically registers a device named "Siphon ETL Engine" and creates the configured entity under it in Home Assistant.
The sink is component-aware: the component field determines which MQTT topics are included in the discovery payload
and where Send() routes its output. All topics are auto-generated from the base path
{discovery_prefix}/{component}/{object_id} and can be individually overridden.
| Component | Topics in Discovery | Send() routes to |
|---|---|---|
sensor, binary_sensor |
state_topic |
state_topic |
device_automation |
topic |
topic |
Availability is managed automatically via MQTT Last Will and Testament (LWT): Home Assistant marks the entity "Unavailable" if Siphon disconnects unexpectedly, and "Online" upon reconnection.
When running as a Home Assistant Add-on, MQTT connection details are injected automatically.
Parameters (params):
url(required): The MQTT broker connection string (e.g.,tcp://192.168.1.100:1883). Auto-injected as an Add-on.user: MQTT username. Supports%%ENV_VAR%%substitution.pass: MQTT password. Supports%%ENV_VAR%%substitution.object_id(required): The entity ID in Home Assistant (e.g.,aggregated_power→sensor.aggregated_power).name: The friendly display name of the entity (default: derived fromobject_id).component: The Home Assistant component type (default:sensor). Controls topic selection — see table above.device_class: The HA device class (e.g.,power,temperature).state_class: The HA state class (e.g.,measurement,total_increasing).unit_of_measurement: The unit displayed in HA (e.g.,W,°C).icon: The MDI icon (e.g.,mdi:flash).state_topic: Override the auto-generated state topic.trigger_type: HA trigger type (fordevice_automation).subtype: HA trigger subtype (fordevice_automation).payload: Optional exact-match payload for the trigger.availability_topic: Override the auto-generated availability topic.
Sensor example:
1sinks:
2 custom_ha_sensor:
3 type: hass
4 params:
5 url: "%%MQTT_HOST%%"
6 user: "%%MQTT_USER%%"
7 pass: "%%MQTT_PASS%%"
8 object_id: "aggregated_power"
9 name: "Total House Power Draw"
10 component: "sensor"
11 device_class: "power"
12 state_class: "measurement"
13 unit_of_measurement: "W"
14 icon: "mdi:flash"
15 # state_topic auto-generated: homeassistant/sensor/aggregated_power/state
Device Trigger example (e.g., Garmin watch trigger):
1sinks:
2 garmin_trigger:
3 type: hass
4 params:
5 url: "%%MQTT_HOST%%"
6 object_id: "garmin_button"
7 component: "device_automation"
8 trigger_type: "button_short_press"
9 subtype: "button_1"
10 icon: "mdi:watch"
11 # topic auto-generated: homeassistant/device_automation/garmin_button/action
Example sink definition
1sinks:
2 local_debug:
3 type: stdout
4 mobile_alerts:
5 type: gotify
6 params:
7 url: "https://gotify.example.com"
8 token: "%%GOTIFY_TOKEN%%"
9 broker_out:
10 type: mqtt
11 params:
12 url: "tcp://192.168.1.100:1883"
13 user: "%%MQTT_USER%%"
14 pass: "%%MQTT_PASS%%"
15 topic: "siphon/processed_data"
16 qos: 1
17 retained: false
Pipelines & Parsers
Pipelines are the primary processing units in Siphon. They act as consumers of the internal Event Bus, defining how raw data is transformed and where it is eventually dispatched.
Pipeline Fields
name(required): A unique identifier for the pipeline.type: Defines the trigger mechanism.event(default): Executes as soon as new data arrives on a subscribed topic.cron: Executes based on a temporal schedule.
topics(required): A list of internal bus topic aliases this pipeline subscribes to.schedule: Required iftypeiscron. Uses standard cron syntax (e.g.,*/5 * * * * *).stateful: (boolean) Whentrue, Siphon caches the last known variables from this pipeline's parser. This is essential for merging data from multiple sources in acronpipeline.bus_mode:volatile(default): High-performance in-memory processing.durable: (WIP) Persists events to a Write-Ahead Log to prevent data loss during restarts.
The parser Block
The parser converts raw bytes from the collector into structured variables.
type: The engine used for extraction.jsonpath: For structured JSON payloads.regex: For extracting values from unstructured strings or logs.
vars: A map where the key is the variable name and the value is the path or pattern.
The transform Block (Optional)
An optional ordered array of expr expressions to further process variables before they hit the sinks. The array
form guarantees that transformations are applied in the order they are defined, which is important when one
transformation depends on the result of a previous one.
1transform:
2 - temp_f: "(temp_c * 9/5) + 32"
3 - temp_f_str: "string(temp_f) + '°F'"
Note: The
transformblock was changed from a map to an array in order to guarantee evaluation order. Please update any existing configurations accordingly.
Topic-Namespaced Variables
In stateful pipelines that subscribe to multiple upstream topics, variables from each source pipeline are accessible
via their pipeline name as a namespace, using the ?. safe-navigation operator.
For example, if a stateful cron pipeline subscribes to process_temp and process_uptime:
1spec: |
2 {
3 "temp": process_temp?.temp ?? 0,
4 "uptime": process_uptime?.up ?? 0
5 }
This prevents panics when a source pipeline hasn't yet reported data.
The sinks Array
Defines the egress routing for the pipeline.
name: The alias of a globally defined sink.format: The rendering engine used for the payload.expr: Uses the expression engine to build complex JSON or logic.template: Uses standard Gotext/templatesyntax.
spec: The actual expression or template string defining the output.
Example pipeline definition
1pipelines:
2 - name: process_garage
3 type: event # Triggers instantly when new data arrives
4 topics: ["garage_telemetry"]
5 parser:
6 type: jsonpath
7 vars:
8 door_state: "$.door.open"
9 battery_v: "$.voltage"
10 transform:
11 - door_state: "string(door_state)"
12 - battery_v: "battery_v / 1000"
13 sinks:
14 - name: alert_phone
15 format: expr
16 spec: |
17 {
18 "title": "Garage Update",
19 "door": door_state,
20 "battery": battery_v
21 }
Advanced: Stateful Cron Merging
Because the Event Bus caches the parsed state, a cron pipeline can wake up on a schedule, fetch the latest states from completely different collectors, and merge them into a single payload using the expr engine. Variables from each source pipeline are accessed using the pipeline name as a namespace prefix.
1pipelines:
2 - name: outdoor_temp
3 topics: ["outdoor"]
4 parser:
5 type: jsonpath
6 vars:
7 state: "$.state"
8
9 - name: garage_telemetry
10 topics: ["garage"]
11 parser:
12 type: jsonpath
13 vars:
14 battery_v: "$.voltage"
15
16 - name: unified_dispatcher
17 type: cron
18 stateful: true
19 schedule: "*/30 * * * * *" # Run every 30 seconds
20 topics: ["outdoor_temp", "garage_telemetry"]
21 sinks:
22 - name: my_backend
23 format: expr
24 spec: |
25 {
26 "merged_telemetry": {
27 "temp": outdoor_temp?.state ?? 0,
28 "garage_v": garage_telemetry?.battery_v ?? 0
29 }
30 }
Note the use of the
??null-coalescing operator and?.safe-navigation in the expr block to prevent panics if a collector hasn't reported data yet.