pyrtan / examples / room-temperature / room-temperature.toml
2,453 bytes · last changed 2026-10-26 in Watches and growing from a gap: trees that run when something speaks, and the branch a gap asks for drafted by rules; release 0.9.0
| 1 | # The temperature a room's sensor last published, over MQTT. A queue node |
| 2 | # subscribes to a topic and waits for one message (an act node publishes |
| 3 | # one). The broker must be in `hosts`, the topic under `topics`; both are |
| 4 | # checked at run time when they come from the sentence. |
| 5 | |
| 6 | name = "room-temperature" |
| 7 | version = 2 |
| 8 | namespace = "pyrtan" |
| 9 | description = "The temperature a room's sensor last published, over MQTT." |
| 10 | tags = ["home", "mqtt"] |
| 11 | license = "MIT" |
| 12 | hosts = ["broker.local"] |
| 13 | topics = ["home/+/temperature"] |
| 14 | start = "wait" |
| 15 | |
| 16 | [[triggers]] |
| 17 | pattern = "[what's the] temperature in the {room:word}" |
| 18 | [[triggers]] |
| 19 | pattern = "how warm is the {room:word}" |
| 20 | |
| 21 | [inputs.room] |
| 22 | type = "str" |
| 23 | default = "kitchen" |
| 24 | pattern = "^[a-z0-9-]+$" |
| 25 | |
| 26 | # Also on its own: every reading the kitchen's sensor publishes runs the |
| 27 | # tree (the run then takes the next message on the topic; a watch on the |
| 28 | # same topic as the tree reads is the simplest shape, not the only one). |
| 29 | [[watches]] |
| 30 | queue = { url = "mqtt://broker.local", topic = "home/kitchen/temperature" } |
| 31 | inputs = { room = "kitchen" } |
| 32 | |
| 33 | [nodes.wait] |
| 34 | kind = "observe" |
| 35 | queue = { url = "mqtt://broker.local", topic = "home/{{ inputs.room }}/temperature" } |
| 36 | into = "q" # state.q = { url, topic, received, message = { topic, body, json }, body, json } |
| 37 | timeout = 15 |
| 38 | retries = 0 |
| 39 | next = "got" |
| 40 | |
| 41 | [nodes.got] |
| 42 | kind = "decide" |
| 43 | on = "q.received" |
| 44 | branches = [{ when = { eq = true }, then = "reading" }, { else = "quiet" }] |
| 45 | |
| 46 | [nodes.reading] |
| 47 | kind = "decide" |
| 48 | on = "q.json.temperature" |
| 49 | branches = [ |
| 50 | { when = { lt = 16 }, then = "cold" }, |
| 51 | { when = { lt = 26 }, then = "fine" }, |
| 52 | { when = { gte = 26 }, then = "warm" }, |
| 53 | ] |
| 54 | |
| 55 | [nodes.cold] |
| 56 | kind = "done" |
| 57 | say = "{{ inputs.room }}: {{ state.q.json.temperature }}°C, cold." |
| 58 | output = { room = "{{ inputs.room }}", temperature = "{{ state.q.json.temperature }}", topic = "{{ state.q.message.topic }}" } |
| 59 | |
| 60 | [nodes.fine] |
| 61 | kind = "done" |
| 62 | say = "{{ inputs.room }}: {{ state.q.json.temperature }}°C." |
| 63 | output = { room = "{{ inputs.room }}", temperature = "{{ state.q.json.temperature }}", topic = "{{ state.q.message.topic }}" } |
| 64 | |
| 65 | [nodes.warm] |
| 66 | kind = "done" |
| 67 | say = "{{ inputs.room }}: {{ state.q.json.temperature }}°C, warm." |
| 68 | output = { room = "{{ inputs.room }}", temperature = "{{ state.q.json.temperature }}", topic = "{{ state.q.message.topic }}" } |
| 69 | |
| 70 | [nodes.quiet] |
| 71 | kind = "fail" |
| 72 | reason = "no-reading" |
| 73 | say = "Nothing on home/{{ inputs.room }}/temperature within 15 s; is the sensor publishing?" |