I am trying to make a sensor that updates every 24 hrs and checks if the value the last day is larger than the ones it has initialized each month and if so replaces the lowest value and hopefully retains its value on restarts.
I have struggled to get this to work starting with a trigger sensor and failing to get it to initialize I figured it could be solved to use an action to set the value of a input_text instead so what I have now is:
updates every 24hrs
checks the value in an input_text
converts the value from string to list to dictionary for processing
compares the current days value against the input_text values
output the value (this is where it works in the template editor but not when I am putting it into config.yaml ).
My current guess is it is a scope issue … that this variable setup worked in a template sensor to move values to the sensor, maybe it doesn’t get to the action for the input_text?
my yaml (trigger no longer with sensor but action input_text that also does not work) (but the action part works in template designer, but so did it when it was a sensor :S … so maybe there is something else?):
Summary
- trigger:
- trigger: time
at: "01:10:00"
- trigger: state
entity_id:
- input_button.trigger_to_test
from: null
to: null
action:
sequence:
- variables:
results: >
{% set ev = states.sensor.value_each_day.state | float %}
{% set evts = as_timestamp(states.sensor.value_each_day.last_updated) %}
{% if states.input_text.monthly_peak_values.state in ["[]",'', ""] %}
{% set in_dict =
{ -0.0001: '1 as_timestamp( states.sensor.*.lastupdated)',
-0.001: '2 as_timestamp( states.sensor.*.lastupdated)',
-0.01: '3 as_timestamp( states.sensor.*.lastupdated)' } %}
{% else %}
{% set in_dict = dict.from_keys(states.input_text.monthly_peak_values.state) %}
{% endif %}
{% set in_eid = in_dict.get(in_dict.keys() | sort()
| select('<=', ev | float(0))
| first, false ) %}
{% set ns = namespace( kvps=[], d={}, l=[] ) %}
{% if in_eid != false %}
{%- for key, value in in_dict | dictsort() %}
{% if in_eid == in_dict[key] %}
{% set ns.kvps = ns.kvps + [(ev, evts)] %}
{% set ns.l = ns.l + [[ev, evts]] %}
{% else %}
{% set ns.kvps = ns.kvps + [(key, value)] %}
{% set ns.l = ns.l + [[key, value]] %}
{% endif %}
{% endfor %}
{% set ns.d = dict.from_keys(ns.kvps) %}
{% else %}
{% set ns.d = in_dict.copy() %}
{% endif %}
{# result to send, example:
data: '[[1.52, 1741481785.820026], [-0.001, '2 as_timestamp( states.sensor.*.lastupdated)'], [-0.0001, '1 as_timestamp( states.sensor.*.lastupdated)']]' #}
data: '{{ ns.l |list }}'
{% set av = dict.from_keys(ns.kvps | selectattr( 0, 'gt', 0.001 ) | list) %}
result_average: '{{ av | average | float }}'
- action: input_text.set_value
target:
entity_id: input_text.monthly_peak_values
data:
value: '{{ data }}'
input_text:
monthly_peak_values :
name: monthly peak values
initial: "[]"
max: 255
Like Hellis81, it isn’t exactly clear to me what you are actually trying to do… but one thing you are doing wrong is using a variable data that has no value. As configured in your example there is only one variable i.e. results… and it doesn’t return a dictionary, just a dictionary-shaped string.
If this is a sensor, where is the sensor portion of the configuration? That is a required component… the configuration will not be loaded if it is missing.
I get what I expect in the template designer but moving it to the config has not worked first as a sensor and now I was trying using an input_text which I thought was better in that I could at least initialize it.
@Didgeridrew I put in a sensor again, it has been there originally but it has not helped me gain what I expect. I also removed the sequence I included it as I was trying to figure out why the action seemed to not get the value that I get in the template designer.
by data having no value is this because of scoping as that is what I was guessing. Originally I had data in the sensor, but it relied on the value of it to calculate it (i believe)
could it be to use the text_input to feel the sensor attribute “data” with the stringified list?
Same issue… you don’t have a variable result_average that has an assigned value. If you want results to return a functional dictionary instead of a dictionary-shaped string, you need to set it up to do that:
...
{% set av = dict.from_keys(ns.kvps | selectattr( 0, 'gt', 0.001 ) | list) %}
{{ {"data": ns.l |list, "result_average": av | average | float } }}
Then you use the proper variable notation like results.result_average for your sensor state(s).
As far as I can tell there is no reason to use an Input text… just add another entry under the sensor key for monthly peak values.
Don’t leave anything in the template that isn’t used, it will just cause trouble… if not now, then in 6 months or a year when you need to make adjustments and you can’t remember what it all does.
thanks for this, it really helped in the end and gave me some great lessons learned. thank you.
lessons learned where I went wrong
I think you meant and I didn’t at first understand was that the scope was wrong not having a ‘results’ - the things I was trying to pass were within the scope of results and they needed to take results and pass it on as I understand as this is working. I also had tried so many things that I had made some type mistakes making things hard in the end to debug.
anyway, here is working code, cleaned up and with the orphan dictionary removed
input needed : sensor.peak_per_day >> a sensor where the peak each day is registered
ouput is in terms of a list and average value in the sensor
notes:
a. number of items in the dictionary “in_dict” will provide the number of values it will save… so it shows 3 but it couild be 5 if you add 2 more - set values appropriately.
b. there is no check (currently) when it is run multiple times a day so it can fill the values with the same value
c. shift in time / day (there is probably a better way to do this) : the trigger is at 01:00 not 00:00 as the peak is finally calculated with the saved value of the last hour at 01:00. Similarly i reset the values on the 2nd each month in the first if in the code as the 1st of each month will include the full last day of the previous month,
- trigger:
- trigger: time
at: "01:10:00"
- trigger: state
entity_id:
- input_button.manual_trigger_for_this_top_values_per_month
from: null
to: null
action:
- variables:
results: >
{% set ev = states.sensor.peak_per_day.state | float %}
{% set evts = as_timestamp(states.sensor.peak_per_day.last_updated) %}
{% if states.sensor.peaks_per_month.attributes.data in ["[]", "", [] ] or (now().strftime("%d") | int) == 2 %} %}
{% set in_dict =
{ -0.0001: '1 as_timestamp( states.sensor.*.lastupdated)',
-0.001: '2 as_timestamp( states.sensor.*.lastupdated)',
-0.01: '3 as_timestamp( states.sensor.*.lastupdated)' } %}
{% else %}
{% set in_dict = dict.from_keys(states.sensor.peaks_per_month.attributes.data) %}
{% endif %}
{% set in_eid = in_dict.get(in_dict.keys() | sort()
| select('<=', ev | float(0))
| first, -1 ) %}
{% set ns = namespace( kvps=[], d={}, l=[] ) %}
{%- for key, value in in_dict | dictsort() %}
{% if in_eid == in_dict[key] %}
{% set ns.kvps = ns.kvps + [(ev, evts)] %}
{% set ns.l = ns.l + [[ev, evts]] %}
{% else %}
{% set ns.kvps = ns.kvps + [(key, value)] %}
{% set ns.l = ns.l + [[key, value]] %}
{% endif %}
{% endfor %}
{% set av = dict.from_keys(ns.kvps | selectattr( 0, 'gt', 0.001 ) | list) %}
{{ ns.l | list, av | average | float }}
{# results to send, like:
([[1.34, 1741602374.850404], [-0.001, '2 as_timestamp( states.sensor.*.lastupdated)'], [-0.0001, '1 as_timestamp( states.sensor.*.lastupdated)']], 1.34) #}
datas: '{{ results[0] | list }}'
result_average: '{{ results[1] }}'
sensor:
- name: "peaks per month"
unique_id: 17d7a988-----unique_id_here
state: '{{ result_average }}'
attributes:
data: '{{ datas }}'