pjvenda
(Pedro venda)
November 28, 2023, 10:59pm
1
I am trying to develop a binary sensor that:
Searches through an array containing dates (sample to follow)
Checks whether each date is today but in the future
Currently the jinja2 for loop iterates through the elements but the ‘flag’ variable never switches to ‘True’.
Please see sample below from the sensor I am trying to parse:
planned_dispatches: [{'start':'2023-11-29T01:30:00.000000+00:00','end':'2023-11-29T02:30:00.000000'}]
completed_dispatches: []
data_last_retrieved: "2023-11-28T22:53:03.198352+00:00"
last_evaluated: "2023-11-28T22:53:03.198984+00:00"
icon: mdi:power-plug-battery
friendly_name: Octopus intelligent dispatching
And here is the jinja2 code I am using, which is not setting the variable/namespace cs_left_today.value
to True
:
{% set planned_dispatches=state_attr('binary_sensor.octopus_energy_a_14bee0dd_intelligent_dispatching','planned_dispatches') %}
{% set cs_left_today = namespace(value=False) %}
{% if planned_dispatches %}
{% set now_ts=as_timestamp(now())|int %}
{% set tomorrow_ts=as_timestamp(now().replace(hour=23, minute=59, second=59))|int+1 %}
{% for pd in planned_dispatches %}
{% if pd is set %}
{% set test_ts=as_timestamp(pd['start'])|int %}
{% if test_ts >= now_ts and test_ts < tomorrow_ts %}
{% set cs_left_today.value = True %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{{ cs_left_today.value }}
Can anybody give me a hand with this please?
pedolsky
(Pedolsky)
November 29, 2023, 6:45am
2
pjvenda:
{% if pd is set %}
Use {% if pd is iterable %}
iterable
(a value that can be iterated over such as a list
, set
, string
, or generator),
Type Checking
1 Like
Troon
(Troon)
November 29, 2023, 7:23am
3
Off-topic for the question itself, but this can be done without a loop, if I’ve understood the request correctly. This returns true
if there is a start
timestamp in that attribute’s list that is in the future and in the current day:
{{ state_attr('binary_sensor.octopus_energy_a_14bee0dd_intelligent_dispatching','planned_dispatches')
| map(attribute='start')
| select('>', now().isoformat())
| select('<', (now()+timedelta(days=1)).isoformat()[:10])
| list | count > 0 }}
Relies on the time format in the attribute matching the isoformat
, which it does on my system in the template editor.
2 Likes
pjvenda
(Pedro venda)
November 29, 2023, 10:35am
4
Thanks - I’ll tweak that!
pjvenda
(Pedro venda)
November 29, 2023, 10:37am
5
Your jinja2 skill level is way above mine. I will give that a try and it might just be the solution. But I would still like to get the loop working, it’s bugging me.
Troon
(Troon)
November 29, 2023, 11:14am
6
@pedolsky solved your problem above. This currently returns true
with the start
at 21:30 today:
{% set planned_dispatches=[{'start':'2023-11-29T21:30:00.000000+00:00','end':'2023-11-29T02:30:00.000000'}] %}
{% set cs_left_today = namespace(value=False) %}
{% if planned_dispatches %}
{% set now_ts=as_timestamp(now())|int %}
{% set tomorrow_ts=as_timestamp(now().replace(hour=23, minute=59, second=59))|int+1 %}
{% for pd in planned_dispatches %}
{% if pd is iterable %}
{% set test_ts=as_timestamp(pd['start'])|int %}
{% if test_ts >= now_ts and test_ts < tomorrow_ts %}
{% set cs_left_today.value = True %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{{ cs_left_today.value }}
1 Like
TheFes
(The Fes)
November 29, 2023, 12:29pm
7
I would use datetime instead of timestamps
{% set planned_dispatches=[{'start':'2023-11-29T21:30:00.000000+00:00','end':'2023-11-29T02:30:00.000000'}] %}
{% set cs_left_today = namespace(value=False) %}
{% if planned_dispatches %}
{% set now_dt = now() %}
{% set tomorrow_dt = today_at() + timedelta(days=1) %}
{% for pd in planned_dispatches %}
{% if pd is mapping %}
{% set test_dt = as_datetime(pd['start']) %}
{% if now_dt < test_dt <= tomorrow_dt %}
{% set cs_left_today.value = True %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{{ cs_left_today.value }}
1 Like
petro
(Petro)
November 29, 2023, 1:16pm
8
Just keep in mind that your end
time doesn’t have a timezone, which will throw off all calculations you use. Especially if you go with datetimes over timestamps (which I also recommend). So when you start incorporating end
in other calc’s, you’ll need a timezone.
1 Like
pjvenda
(Pedro venda)
December 1, 2023, 9:46am
9
Thanks - I don’t mind playing with timestamps and ensuring that everything is a timestamp seemed feasible, but I agree this solution is more elegant. I will incorporate and report back.
pjvenda
(Pedro venda)
December 1, 2023, 9:48am
10
Thanks, though I am not sure I fully understand what you mean.
I can’t do much about the array/list I’m given in the sensor, I believe they have a timezone (+00:00
).
Are you suggesting that I ensure the timezones are set for the datetimes I use for comparison - today/now/tomorrow, etc?
TheFes
(The Fes)
December 1, 2023, 10:16am
11
The value for end
in your example doesn’t have a timezone, so if you also want to start using that, you will get errors because it can’t compare a datetime with a timezone to a datetime which isn’t timezone aware
1 Like
petro
(Petro)
December 1, 2023, 11:22am
12
This has a timezone +00:00
This does not
If you use end
with | as_datetime
, you will not be able to use it in calculations because the code won’t know what timezone the time is in.
1 Like
pjvenda
(Pedro venda)
December 1, 2023, 12:04pm
13
TheFes:
end
gotcha - it could have been a copy+paste/retyping error. that said, I can’t control it, but I will check next time the sensor has values.
petro
(Petro)
December 1, 2023, 12:06pm
14
You can always add the timezone to the string if you know what it is.
1 Like
pjvenda
(Pedro venda)
December 13, 2023, 11:27am
15
Just wanted to close this off by saying that I got the sensors working. The main error was bad type checking. The main improvement was using datetime instead of timestamp.
Thanks all!