Note specifically how this can have a latest value from attributes that can be referenced in the state, but not the other way around. I find this odd.
Here’s why: I just defined this helper sensor for my irrigation and I want to separate state values from what’s displayed on the UI. I need to define this in the sensor, as there’s no way with built-in cards to map from states to UI strings.
Before I read the documentation with more attention, I naturally thought it would work the other way around: Compute your new state, and have that available for use in icon and attribute fields.
I was wondering whether there’s a particular reason it would’ve been implemented this way. Attributes are secondary to the state, but this gives it a weird kind of primary status.
I don’t see how your state template will ever return anything but manual_zone… this.state will return the existing state of sensor.irrigation_state at the time of the trigger. However, none of the values you are testing against match values your template will return.
The state uses the now() from the attribute from the same event it’s updated from. In other words, in this case, sensor.test.state == sensor.test.attributes.test.
EDIT: Extra note: My state template merely “translates” the “internal state value” to one I can use on the UI. (Correction: It’s the reverse.)
The example from the docs has two major difference from the original post; the state template references an attribute of this not it’s state, and it is not trigger-based.
The order of operations for a trigger-based template sensor is trigger > instantiate this and trigger variables > render state > render attributes…
If sensor.test from the docs were trigger-based (and the templates were fixed to handle the initial case where this is undefined) the state value would always be the value of the test attribute saved at the last firing… there is no cyclic re-rendering of state based on the value of test because test is not a trigger.
template:
- trigger:
- platform: state
entity_id: input_boolean.this_is_a_test
from: null
sensor:
- name: This Is A Test
unique_id: 961b6c02-7b7e-416e-913e-8ee10fb73901
state: "{{ trigger.to_state.state }}"
attributes:
test: "The input boolean is {{ this.state }}"
- name: This Is A Test 2
unique_id: 67fa65f3-0cfb-4795-8a3e-45f95f42fef1
state: "The input boolean is {{ this.attributes.test | default() }}"
attributes:
test: "{{ trigger.to_state.state }}"
- sensor:
- name: This Is A Test 3
unique_id: a82e6278-7db6-4961-908c-0eb4514eccf3
state: "{{ states('input_boolean.this_is_a_test') }}"
attributes:
test: "The input boolean is {{ this.state }}"
- name: This Is A Test 4
unique_id: 841692d6-d3ef-47e2-bd07-81b4f9c55e09
state: "The input boolean is {{ this.attributes.test | default() }}"
attributes:
test: "{{ states('input_boolean.this_is_a_test')}}"
So, from this I conclude that the this object doesn’t change for trigger based template sensors after the trigger.
For non triggered sensors it does change during rendering of the template, or maybe it listens to state changes of itself. Not completely sure about that, I would need to dig in the code for that, and I’m not sure if I already have enough Python knowledge for that.
I see now what you originally meant, @Didgeridrew. It’s just strange, because the sensor does change state as expected when turning on and off that switch.
I will make some changes tomorrow and test this again.
Just to highlight my original point though: The example in the docs seem to say you can change an attribute and then reference that current (new) value through this in the state. The one strange thing I’ve mentioned is that if something like that were to work, I would’ve though the state would be set first and then one can use that value in attributes. Secondly, I always thought (since its introduction) that this is always the previous (last) state.
Yes, you can do that, but not when you use a trigger. If you use a trigger, the this object is generated at the moment of the trigger, and it doesn’t change (exactly the same as it does for an automation).
That only works with the example because the attribute template will spark a state change for the main state template. As soon as you add a trigger to the mix, that behavior changes because the trigger determines the updates.
Without a trigger, templates update based on the entities that the template is listening to.
With a trigger, the trigger causes the templates to execute, nothing else.
I find this all very opaque. Your explanations are great. I’m referring to how one would get to learn this purely from the docs.
Is this documented somewhere that I have missed, or is it just the fact that one has to understand the implied subtleties in detail? Like the given example: unless there’s a second example, it’s very hard to spot what parts make the difference. At least for me that is.
Is it stands, I feel like rather duplicating my logic, because from a maintenance point of view I won’t need to remember any of the discussion a yest from now. All I wanted to do was to avoid the duplication. Perhaps I shall just use a Jinja macro instead.
I’d be happy to submit changes for the docs (as I have before), but I can only do it when I really understand what’s going on.
Honestly, I’m not ranting here.
EDIT: I read about 6 forum posts about this and 2 GitHub issues of which one was an actual bug (when this was added), but I really didn’t pick up on any of this. Not saying the info wasn’t there though.
@Didgeridrew@TheFes@petro thank you for all your help and clarifications, and I need to apologise, because I certainly stuffed something up during my testing. I think I deployed the code I posted initially, but never reloaded/restarted (I can write a long story as an explanation, but basically it involves a baby and the lack of sleep).
Without making any changes, I simply reran it and got the incorrect results: