The issue you have is a real thing and not just “Fix your WiFi.” Stuff in the real world happens, and systems should be resilient.
The problem you have is a real one, not just “fix your WiFi”. Unexpected things happen in the real world and systems should be resilient.
A state-based model with a constraint-solving system would be very nice indeed, and could enable very simple yet powerful automations that have self-healing capabilities.
Imagine you define a constraint: When it’s evening, then the lights’ temperature should be 2500K. Then it doesn’t matter what happens to the light, if it is turned on via an external switch (so not controlled by HA), or an automation (controlled by HA), or if it is already on and needs adjustment. (No event that turned on the light.)
(There are integrations like Adaptive Lighting, that work like this.)
The problem with such a system is that it’s much harder to implement.
It would be a terrible waste of resources if the system had to check every constraint in a loop as fast as possible. Instead, the system would have to work out when to do the checks. (i.e. When the lights go on/off. When HA finishes booting, When the light is reconnected, …)
For practical advice that you can follow with any automation:
Don’t use the automation triggers for your logic.
Trigger: Sun sets
Actions: Turn on the light
Bad: There isn’t really a check if the sun has set. This would break if you run the automation with automation.trigger
or add another trigger in the future.
Better:
Triggers:
- Sun sets
- Someone comes home
Conditions:
- Sun below horizon
- Someone at home
Actions: Turn on the light
If you want the conditions to be checked even when you run the automation by hand, then move the conditions to the actions section.
- For such “constraint automations”, consider adding a special label and then adding an automation that triggers on major events and coordinates the checks. You can use this as a strategy to dynamically decide how often to run the checks, saving resources.
triggers:
- trigger: homeassistant
event: start
- trigger: state
entity_id:
- binary_sensor.connected_to_the_internet
- trigger: time_pattern
minutes: /10
actions:
- action: automation.trigger
data:
skip_condition: false
target:
label_id: constraint
A central coordinator could also be useful if, for example, you have an automation A that needs to run to provide the condition for automation B.
- You can catch call_service events, fix the situation and send the event again.
For example, I have a network switch connected to a smart plug.
For a wake-on-lan event to reach my PC, the switch and therefore the plug must be turned on.
So the following automation triggers when the WoL button is pressed and the plug is off, then turns the plug on, waits until the network switch is on and then tries to turn the PC on again.
alias: When computer WoL and outlet off -> turn on outlet and re-emit
description: ""
triggers:
- alias: When Bob WoL is called
trigger: event
event_type: call_service
event_data:
domain: button
service: press
service_data:
entity_id: button.bob_wol
conditions:
- condition: state
entity_id: switch.outlet
state: "off"
actions:
- action: switch.turn_on
target:
entity_id: switch.outlet
- alias: Wait for network switch to be available
wait_for_trigger:
- trigger: state
entity_id:
- device_tracker.switch_wohnzimmer
to: home
timeout:
minutes: 1
- action: button.press
target:
entity_id:
- button.computer_wol
Or re-emit the event as is:
- event: call_service
event_data:
domain: "{{ trigger.event.data.domain }}"
service: "{{ trigger.event.data.service }}"
data: "{{ trigger.event.data.service_data }}"
There is a possibility of creating an endless loop, so be careful with this type of automation.