Rules are WarLink's unified automation system. A rule monitors one or more PLC tag conditions and executes actions when conditions are met. Rules replace the separate Triggers and Push systems from earlier versions, combining their capabilities into a single, more flexible framework.
Each rule consists of:
- Conditions — One or more PLC tag conditions combined with AND or OR logic
- Actions — Executed on rising edge (conditions become true): publish to MQTT/Kafka, send HTTP webhooks, or write values to PLC tags
- Cleared actions (optional) — Executed on falling edge (conditions go back to false)
rules:
- name: ProductComplete
enabled: true
conditions:
- plc: MainPLC
tag: Program:MainProgram.ProductReady
operator: "=="
value: true
logic_mode: and # "and" (default) or "or"
debounce_ms: 100
cooldown_ms: 5000 # Minimum interval before re-arming
actions:
- type: publish
tag_or_pack: pack:ProductionMetrics
include_trigger: true
mqtt_broker: all
kafka_cluster: ProductionKafka
kafka_topic: production-events
- type: writeback
write_tag: Program:MainProgram.ProductAck
write_value: 1
cleared_actions:
- type: writeback
write_tag: Program:MainProgram.ProductAck
write_value: 0See Configuration Reference for the full field reference.
Each condition references a PLC, tag, comparison operator, and value:
conditions:
- plc: MainPLC
tag: Program:MainProgram.Temperature
operator: ">"
value: 100
- plc: MainPLC
tag: Program:MainProgram.AlarmBit
operator: "=="
value: true| Operator | Description |
|---|---|
== |
Equal to |
!= |
Not equal to |
> |
Greater than |
< |
Less than |
>= |
Greater than or equal |
<= |
Less than or equal |
| Mode | Behavior |
|---|---|
and (default) |
All conditions must be true to fire |
or |
Any single condition being true fires the rule |
Add not: true to a condition to invert its result:
conditions:
- plc: MainPLC
tag: RunningFlag
operator: "=="
value: true
not: true # Fires when RunningFlag is NOT trueRules support three action types. A single rule can have multiple actions of any type, and they execute in parallel when the rule fires.
Captures tag or TagPack data and publishes to MQTT and/or Kafka.
actions:
- type: publish
tag_or_pack: pack:ProductionMetrics # "pack:Name" for TagPacks, or a tag name
include_trigger: true # Include condition tag values in message
mqtt_broker: all # "all", "none", or a specific broker name
mqtt_topic: rules/ProductComplete # Custom MQTT sub-topic (default: rules/{rule-name})
kafka_cluster: all # "all", "none", or a specific cluster name
kafka_topic: production-events # Custom Kafka topic suffix (default: rules)Service selection:
| Value | Behavior |
|---|---|
all |
Publish to all configured brokers/clusters (default) |
none |
Disable publishing to this service |
{name} |
Publish only to the named broker/cluster |
MQTT publishes with QoS 2 (exactly-once delivery).
Sends an HTTP request to an external endpoint with body template support.
actions:
- type: webhook
name: SlackAlert # Label for logging
url: https://hooks.slack.com/services/T00/B00/xxxx
method: POST # GET, POST, PUT, PATCH (default: POST)
content_type: application/json
body: '{"text": "Alarm on MainPLC, temp: #MainPLC.Temperature"}'
headers:
X-Source: warlink
auth:
type: bearer
token: "your-api-token"
timeout: 30sBody templates — Use #PLCName.tagName references in the body to include live tag values. References are resolved at send time. If a tag cannot be read, the reference is left as-is.
Authentication types:
| Type | Fields | Description |
|---|---|---|
bearer |
token |
Sends Authorization: Bearer <token> |
jwt |
token |
Same as bearer (alias) |
basic |
username, password |
HTTP Basic Authentication |
custom_header |
header_name, header_value |
Custom header (e.g., X-API-Key) |
Writes a value to a PLC tag when the rule fires or clears.
actions:
- type: writeback
write_plc: MainPLC # PLC name (defaults to first condition's PLC)
write_tag: Program:MainProgram.AckFlag
write_value: 1 # Value to write (any type)The write tag must be marked as writable: true in the PLC's tag configuration.
┌──────────┐ conditions ┌──────────┐ actions done ┌─────────────┐
│ Armed │────────────────▶│ Firing │────────────────▶│WaitingClear │
└──────────┘ rising edge └──────────┘ └──────┬──────┘
▲ │
│ │ conditions
│ ┌──────────┐ │ all false
└────────────────────────────│ Cooldown │◀───────────────────┘
interval elapsed └──────────┘ (cleared actions run here)
| State | Description |
|---|---|
| Disabled | Rule is stopped |
| Armed | Monitoring conditions for rising edge |
| Firing | Executing actions |
| Waiting Clear | Actions complete, waiting for conditions to go false |
| Cooldown | Conditions cleared, waiting minimum interval before re-arming |
| Error | Action execution failed |
- Rising edge (false → true): The rule's
actionsfire - Falling edge (true → false): The rule's
cleared_actionsfire (if configured)
This enables patterns like setting an acknowledgment flag when a condition is met and clearing it when the condition resets.
Publish actions produce JSON messages sent to MQTT and Kafka:
{
"rule": "ProductComplete",
"timestamp": "2024-01-15T10:30:00.123456789Z",
"sequence": 42,
"plc": "MainPLC",
"trigger": {
"MainPLC.ProductReady": true
},
"data": {
"ProductionMetrics": {
"MainPLC.Counter": { "value": 1234, "type": "DINT", "plc": "MainPLC" },
"MainPLC.Speed": { "value": 100.5, "type": "REAL", "plc": "MainPLC" }
}
}
}| Field | Description |
|---|---|
rule |
Rule name |
timestamp |
Nanosecond-precision capture time |
sequence |
Incrementing sequence number (resets on restart) |
plc |
First condition's PLC name |
trigger |
Condition tag values (when include_trigger: true) |
data |
Captured tag values and pack data |
| Service | Topic Pattern |
|---|---|
| MQTT | {namespace}/rules/{rule-name} (or custom mqtt_topic) |
| Kafka | {namespace}-rules (or custom kafka_topic) |
Rule list (left pane):
| Key | Action |
|---|---|
a |
Add new rule |
x |
Remove selected rule |
e |
Edit selected rule |
Space |
Toggle enabled/disabled |
F |
Test fire (bypasses conditions and cooldown) |
Tab |
Switch to conditions pane |
Set debounce_ms to prevent rapid re-firing. Condition matches within the debounce window after the last fire are ignored.
Set cooldown_ms to enforce a minimum interval between fires. After conditions clear, the rule waits for the cooldown period before re-arming. During cooldown, the rule will not fire even if conditions become true again.
Test fire executes all actions immediately, bypassing conditions and cooldown. This is useful for verifying endpoint connectivity, message format, and writeback behavior. Test fires increment the fire counter but do not enter cooldown state.
Rules replace both Triggers and Push from v0.2.7 and earlier. To migrate:
Triggers → Create a rule with:
- The trigger's condition as the rule condition
- A
publishaction for the MQTT/Kafka publishing - A
writebackaction for the ack tag (if used)
Push webhooks → Create a rule with:
- The push conditions as rule conditions (set
logic_mode: orif using OR logic) - A
webhookaction with the URL, method, body, and auth settings
rules:
- name: PartComplete
enabled: true
conditions:
- plc: LinePLC
tag: Program:Main.PartReady
operator: "=="
value: true
debounce_ms: 100
cooldown_ms: 1000
actions:
- type: publish
tag_or_pack: pack:PartData
include_trigger: true
kafka_cluster: all
kafka_topic: production-events
- type: writeback
write_tag: Program:Main.PartAck
write_value: 1
cleared_actions:
- type: writeback
write_tag: Program:Main.PartAck
write_value: 0rules:
- name: HighTempAlarm
enabled: true
conditions:
- plc: MainPLC
tag: Temperature
operator: ">"
value: 100
cooldown_ms: 1800000 # 30 minutes
actions:
- type: webhook
name: SlackAlert
url: https://hooks.slack.com/services/T00/B00/xxxx
body: '{"text": "High temperature alarm: #MainPLC.Temperature degrees"}'rules:
- name: QualityCheck
enabled: true
logic_mode: and
conditions:
- plc: LinePLC
tag: BatchComplete
operator: "=="
value: true
- plc: LinePLC
tag: QualityScore
operator: ">="
value: 95
actions:
- type: publish
tag_or_pack: pack:BatchResults
mqtt_broker: all
- type: webhook
url: https://mes.example.com/api/batch-pass
body: '{"batch": #LinePLC.BatchID, "score": #LinePLC.QualityScore}'- Rules fire on rising edge only; cleared actions fire on falling edge
- All actions within a rule execute in parallel
- Sequence numbers reset when WarLink restarts
- Failed actions are logged but do not block other actions
- Writeback failures are logged silently if the PLC is disconnected
- The condition poll interval is 100ms