There seems to be some confusion here. So let’s take a step back.
First, the term “state” has been (unfortunately) overloaded in HA. It sometimes refers to a state object, but it also sometimes refers to the state object’s state string. In fact, I believe in most cases when someone just says “state” they mean the state object’s state string. I’ll try to be very specific…
A state object represents (what I’ll call) the status of an entity at some point in time. As mentioned it contains a state string, which is, again, what most people call the “state” of the entity. But it also (typically) contains one or more attributes.
If any part of the state object changes (i.e., either the state string, or any of the attributes) it will cause a state_changed event. And since there’s a change, that means there’s an old state object that represents the status of the entity before the change, and a new state object that represents the status of the entity after the change.
The state trigger watches for state changes. It may or may not trigger on all state changes. If from:
and to:
are not specified, then it will trigger on every state change, even if that change was only in an attribute.
If from:
and/or to:
are specified, then the state trigger will only trigger when the state string changes as specified by from:
and/or to:
. (To be clear, just an attribute change will not cause a trigger in this case.) If to:
is specified, then the new state string must match it. If from:
is specified, then the old state string must match it. If both are specified then both the new and old state strings must match accordingly.
(Note that when the state trigger actually triggers, trigger.from_state
contains a copy of the old state object, and trigger.to_state
contains a copy of the new state object.)
Now getting back to your question, from:
and/or to:
can be used with any entity, not just a binary one. E.g., let’s say there’s a sensor whose state string can take on the values ‘a’, ‘b’ or ‘c’. If you specify to: a
, then ‘b’->‘a’ will trigger, and ‘c’->‘a’ will also trigger, but ‘b’->‘c’ and ‘c’->‘b’ will not. And if you specify both from: a
and to: b
, then only ‘a’->‘b’ will trigger it, but no other state change will.
Specifying:
condition: template
value_template: "{{ states('binary_sensor.zp_opbrengst_threshold') in ['on','off'] }}"
does not “filter out” attribute changes. It only does what it says. It allows the actions to run if the binary sensor is either ‘on’ or ‘off’ (which it almost always, and possibly always, is. I say almost always, because a binary sensor can sometimes take on other values such as ‘unknown’ or ‘unavailable’. It’s only “binary” in its usual values.)
You can always look at the code. The threshold binary sensor doesn’t just look at the current value of the watched entity to decide if it should be ‘on’ or ‘off’. It also remembers whether the threshold has been crossed. And if you specify hysteresis, that threshold is not a fixed value. E.g., if you specify upper:
, then on the way up the threshold is actually upper + hysteresis. But on the way back down it becomes upper - hysteresis. That’s the whole point (i.e., to implement hysteresis.)