This could be a FAQ, but I did not manage to find any discussion, so here goes …
I expected this automation to set the light to a random color when a movie starts playing:
automation:
- alias: "Apple TV starts playing"
trigger:
- platform: state
entity_id: media_player.apple_tv
to: 'playing'
action:
service: light.turn_on
entity_id: light.movie
data_template:
rgb_color: ['{{ (range(0, 255)|random) }}', '{{ (range(0, 255)|random) }}', '{{ (range(0, 255)|random) }}']
brightness: 80
In real life, though, it keeps changing colors every few seconds while the movie is playing.
What happens is that the entity attributes (the play position in particular) are updated during the play. So HA sees a change in the entity, notices that the target state is ‘playing’ and thus runs the action.
I think this is very confusing. An action can then run due to all kinds of changes that are not mentioned in the automation. Getting it to work like I want requires listing all possible “from” states, except ‘playing’.
So I made this change to see if I could get things working like I expected (this says to only run the action if the mentioned state has actually changed, or if no from/to filters are supplied at all):
--- a/homeassistant/helpers/event.py
+++ b/homeassistant/helpers/event.py
@@ -74,7 +74,9 @@ def async_track_state_change(hass, entity_ids, action, from_state=None,
else:
new_state = None
- if _matcher(old_state, from_state) and _matcher(new_state, to_state):
+ no_filter = (from_state == MATCH_ALL and to_state == MATCH_ALL)
+ any_change = (old_state != new_state)
+ if no_filter or (any_change and _matcher(old_state, from_state) and _matcher(new_state, to_state):
hass.async_run_job(action, event.data.get('entity_id'),
event.data.get('old_state'),
event.data.get('new_state'))
With that code change in place the original behavior can still be achieved by putting the state comparison into a condition. Written like that, this also works like I would expect – the entity has changed and the state is ‘playing’:
- alias: "Apple TV is playing"
trigger:
- platform: state
entity_id: media_player.apple_tv
condition:
- condition: state
entity_id: media_player.apple_tv
state: 'playing'
action:
# ...
This was just a quick test but it makes much more sense to me. So I guess my question is, why is HA not working like that? I must be missing something