Partly cloudy. High (70%) chance of showers in the early morning. Winds west to northwesterly 15 to 20 km/h tending west to southwesterly 25 to 35 km/h in the morning then becoming light in the evening.
I would like to find the maximum from all occurances of numbers between ‘to’ and ‘km/h’ (or 0 if none) .
There can be anywhere from 0 to 4 occurrences of these numbers to choose a maximum from, that I have seen so far.
Here’s what I just spent the last way too many minutes busting my brain to come up with. It’s not pretty but it will work (assuming that the sensor you have outputs the string in the same way every time…).
{% set value = state_attr('sensor.bom_forecast_hobart_1', 'Detailed Summary') %}
{% set array = value.split('km/h')[:-1] %}
{% if array[0] is defined %}
{% set val0 = value | regex_findall_index('(\d+) km/h', index = 0) | int %}
{% else %}
{% set val0 = 0 %}
{%endif%}
{% if array[1] is defined %}
{% set val1 = value | regex_findall_index('(\d+) km/h', index = 1) | int %}
{% else %}
{% set val1 = 0 %}
{%endif%}
{% if array[2] is defined %}
{% set val2 = value | regex_findall_index('(\d+) km/h', index = 2) | int %}
{% else %}
{% set val2 = 0 %}
{%endif%}
{% if array[3] is defined %}
{% set val3 = value | regex_findall_index('(\d+) km/h', index = 3) | int %}
{% else %}
{% set val3 = 0 %}
{%endif%}
{% if array[4] is defined %}
{% set val4 = value | regex_findall_index('(\d+) km/h', index = 4) | int %}
{% else %}
{% set val4 = 0 %}
{%endif%}
{% set max_wind = [(val0), (val1), (val2), (val3), (val4)] |max %}
{{max_wind }}
that will get you the highest reading from a possible 5 values.
No problem. I’m really glad it worked. That one really hurt. but it was definitely fun trying to figure it out.
I spent way more time on it than necessary since the HA docs are wrong (or at least misleading). the templating section where it talks about “regex_findall_index” mentions in parentheses that “findall returns an array of matches”. After jacking around trying to figure out how this “findall” filter was supposed to work, I figured out that there is no other “findall” filter than the “regex_findall_index” filter which DOES NOT return an array that you have any access to.
After I realized that I just channeled my inner 123 & petro and fumbled my way thru till it worked.
But you know they’re probably going to jump in here anytime now and do what I did above in 5 lines of code and embarrass me, right?
It works with any number of "to nn km/h" items it may find in the Detailed Summary. It returns 0 if there are none.
{% set x = state_attr('sensor.bom_forecast_hobart_1', 'Detailed Summary') %}
{% set y = x.split(' km/h')[:-1] %}
{% set items = y | length %}
{% set ns = namespace(max=0) %}
{% for i in range(items) %}
{% set val = y[i] | regex_findall_index('to (\d+)$') | int %}
{% set ns.max = val if val > ns.max else ns.max %}
{% endfor %}
{{ ns.max }}
It uses the same principal employed by finity’s solution by first converting the Detailed Summary into a list. Then it:
Determines the total number of items in the list.
Initializes a global variable called ns.max. The scope of this variable is valid inside and outside the for-loop.
It loops through all items in the list, searching for the upper wind-speed within the item.
It determines if the wind-speed is higher than ns.max. If it is, it becomes the new value for ns.max.
After the for-loop completes checking all items in the list, it exits and the maximum wind-speed is reported.
The solution might have been more compact if Home Assistant’s implementation of Jinja2 supported regex_findall. It returns a list containing the matching strings. It would probably look something like this:
{% set x = state_attr('sensor.bom_forecast_hobart_1', 'Detailed Summary') %}
{{ x | regex_findall('to (\d+) km/h') | max }}
I say “something like” because it makes a huge assumption that the list’s items are integer values (and I suspect they wouldn’t be). My guess is it would probably need to use map to convert the strings into integers before passing the resulting list on to max.
I realized I don’t need regex_findall_index. The use of string slicing is adequate as long as wind-speed never exceeds double-digits. I can also dispense with two temporary variables.
The result is still not 5 statements but 6 (instead of 9).
{% set y = state_attr('sensor.bom_forecast_hobart_1', 'Detailed Summary').split(' km/h')[:-1] %}
{% set ns = namespace(max=0) %}
{% for i in range(y | length) %}
{% set ns.max = y[i][-2:]|int if y[i][-2:]|int > ns.max else ns.max %}
{% endfor %}
{{ ns.max }}
I could move the for-loop’s three statements onto one line, to reduce line-count to 4, but that wouldn’t be cricket.
Although one could use regex_findall_index in the abbreviated version, it would make the statement within the for-loop awfully long. Anyway, that 6-statement version was done for fun. It’s brevity doesn’t make it any easier to understand and it comes with the double-digit limitation.
The only thing I’d change in my original version is to eliminate two temporary variables. It reduces it to 7 statements without any loss of functionality.
{% set y = state_attr('sensor.bom_forecast_hobart_1', 'Detailed Summary').split(' km/h')[:-1] %}
{% set ns = namespace(max=0) %}
{% for i in range(y | length) %}
{% set val = y[i] | regex_findall_index('to (\d+)$') | int %}
{% set ns.max = val if val > ns.max else ns.max %}
{% endfor %}
{{ ns.max }}
I’ve been looking at regular expression evaluators on line and looking up the methods you used. I won’t say I could reproduce it for a different example but I have the beginnings of understanding how it works.