Skip to main content

Tags & Groups

Tags and groups both allow bulk operations on rules, but they serve different purposes.

Tags

Tags are free-form string labels stored on each rule. They are great for open-ended categorization.

Adding tags

In RON:

id      = ""
name = "Deck door open alert"
enabled = true
tags = ["deck", "door-alerts", "security"]

[trigger]
type = "device_state_changed"
...

Via API:

curl -s -X PUT http://localhost:8080/api/v1/automations/RULE_ID \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Deck door open alert",
"enabled": true,
"priority": 10,
"tags": ["deck", "door-alerts"],
"trigger": {...},
"conditions": [],
"actions": [...]
}' | jq

Filtering by tag

# List all deck rules
curl -s "http://localhost:8080/api/v1/automations?tag=deck" \
-H "Authorization: Bearer $TOKEN" | jq '.[].name'

# Count door-alert rules
curl -s "http://localhost:8080/api/v1/automations?tag=door-alerts" \
-H "Authorization: Bearer $TOKEN" | jq length

Bulk enable/disable by tag

# Vacation mode — disable all vacation-sensitive rules
curl -s -X PATCH "http://localhost:8080/api/v1/automations?tag=vacation-sensitive" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"enabled": false}' | jq .updated

# Re-enable on return
curl -s -X PATCH "http://localhost:8080/api/v1/automations?tag=vacation-sensitive" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"enabled": true}' | jq .updated

Suggested tag conventions

CategoryExample tags
Area/room"deck", "garage", "bedroom", "kitchen"
Function"door-alerts", "morning-routine", "security"
Vacation"vacation-sensitive", "presence-aware"
Maintenance"disabled-pending-fix", "seasonal", "testing"

Groups

Groups are named bundles of rule UUIDs stored in rules/groups.json. Unlike tags (stored on each rule), groups reference rules by UUID and survive rule renames.

A rule can belong to multiple groups. Groups do not affect evaluation order or priorities.

Create a group

GROUP_ID=$(curl -s -X POST http://localhost:8080/api/v1/automations/groups \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"id": "",
"name": "Vacation Mode",
"description": "Rules to pause while away from home",
"rule_ids": ["UUID1", "UUID2", "UUID3"]
}' | jq -r .id)

echo "Group: $GROUP_ID"

List and view groups

# List all groups
curl -s http://localhost:8080/api/v1/automations/groups \
-H "Authorization: Bearer $TOKEN" | jq

# Get one group
curl -s http://localhost:8080/api/v1/automations/groups/$GROUP_ID \
-H "Authorization: Bearer $TOKEN" | jq

Update a group

# Change name and description
curl -s -X PATCH http://localhost:8080/api/v1/automations/groups/$GROUP_ID \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Extended Vacation", "description": "Updated vacation rules"}' | jq

# Add a new rule to the group
curl -s -X PATCH http://localhost:8080/api/v1/automations/groups/$GROUP_ID \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"rule_ids": ["UUID1", "UUID2", "UUID3", "UUID4"]}' | jq

Enable / disable all rules in a group

# Disable — leaving for vacation
curl -s -X POST http://localhost:8080/api/v1/automations/groups/$GROUP_ID/disable \
-H "Authorization: Bearer $TOKEN" | jq .updated

# Re-enable on return
curl -s -X POST http://localhost:8080/api/v1/automations/groups/$GROUP_ID/enable \
-H "Authorization: Bearer $TOKEN" | jq .updated

Response: { "enabled": true, "updated": 3, "rules": [...] }

Delete a group

curl -s -X DELETE http://localhost:8080/api/v1/automations/groups/$GROUP_ID \
-H "Authorization: Bearer $TOKEN"

Deleting a group does not delete the rules themselves. It only removes the group definition from rules/groups.json.


Tags vs. Groups — when to use each

TagsGroups
Stored inEach rule's RON filerules/groups.json
Survives rule renameYesYes (by UUID)
One rule, manyYesYes
Bulk toggle APIPATCH /automations?tag=XPOST /automations/groups/ID/enable
Best forOpen-ended labellingNamed presets (vacation, maintenance, testing)
VisibilityAlways visible in rule dataSeparate group objects

Rule of thumb: Use tags when you want the label to travel with the rule (visible in GET /automations). Use groups when you want a named switch that controls a set of rules without editing each one.


Automation list filters

GET /automations accepts these query parameters (all combinable):

ParameterExampleEffect
tag?tag=deckOnly rules containing this tag
trigger?trigger=time_of_dayOnly rules with this trigger type
device_id?device_id=yolink_abcOnly rules referencing this internal device ID (filtering uses the real device_id, even if the rule source uses device = "canonical.name")
stale?stale=trueOnly rules with an error field (broken or references deleted device)
limit?limit=10Pagination
offset?offset=20Pagination offset

X-Total-Count response header gives the total count before pagination:

curl -s "http://localhost:8080/api/v1/automations?tag=security&limit=10" \
-H "Authorization: Bearer $TOKEN" \
-v 2>&1 | grep "X-Total-Count"
# X-Total-Count: 23

Valid trigger values: device_state_changed device_availability_changed time_of_day sun_event cron periodic webhook_received mqtt_message custom_event system_started mode_changed button_event numeric_threshold hub_variable_changed calendar_event manual_trigger


Bulk PATCH

Bulk-update enabled, priority, or tags for multiple rules at once.

# Disable all rules matching a tag
curl -s -X PATCH "http://localhost:8080/api/v1/automations?tag=vacation-sensitive" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"enabled": false}'

# Disable specific rules by ID
curl -s -X PATCH http://localhost:8080/api/v1/automations \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"ids": ["UUID1", "UUID2"], "enabled": false}'

# Disable ALL rules (no filter)
curl -s -X PATCH http://localhost:8080/api/v1/automations \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"enabled": false}'

When ids is present in the body, ?tag= query parameter is ignored.

Response: { "updated": N, "rules": [...full rule objects...] }


Clone a rule

Duplicate a rule with a new UUID. The clone is disabled by default, named Copy of {original}.

curl -s -X POST http://localhost:8080/api/v1/automations/RULE_ID/clone \
-H "Authorization: Bearer $TOKEN" | jq '{id, name, enabled}'
# → { "id": "new-uuid", "name": "Copy of Front door alert", "enabled": false }

Edit the clone's trigger/conditions/actions and enable it when ready.


Export and import

# Export all rules
curl -s http://localhost:8080/api/v1/automations/export \
-H "Authorization: Bearer $TOKEN" > rules-backup.json

# Import (adds rules; does not replace existing ones)
curl -s -X POST http://localhost:8080/api/v1/automations/import \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d @rules-backup.json | jq '{imported: length}'

Imported rules get fresh UUIDs, so there are no ID conflicts with existing rules.