Scenario
Every morning my spouse wants to know the specific temperature and forecast, but she typically asks me assuming Iâve already checked since I get up earlier. Iâm not one who checks the weather, because where we live it is pretty consistent. January - March below freezing, June-August slightly warm, pleasant in between⊠For this I used the Tomorrow.io - Home Assistant integration, but you could probably do it with the default AccuWeather, or whatever you have, as long as it provides an hourly forcast.
The Fix
I made her a notification that answers all her questions!
Why not use a weather app? Because I can do it this with Home Assistant! Wasted time? No! I learned more about Jinja namespaces. Which is annoying but a good learning experience.
Updated version that doesnât use loops or require jinja namespaces
With the help of @CentralCommand in his reply Morning Weather Notification | With daily high temperature đ„ș - #9 by CentralCommand the for loop is not necessary to achieve the same result.
Here is the the updated versionâŠ
Currently {{state_attr('weather.climacell_nowcast','temperature')}}°,
feels like {{states('sensor.climacell_feels_like')}}°.
Today
{{ (state_attr('weather.climacell_hourly', 'forecast')
| map(attribute="temperature")
| list)[0:16]
| max }}°
/{{ state_attr('weather.climacell_daily', 'forecast')[0].templow }}°
{{ states('weather.climacell_daily') }}
humidity {{ state_attr('weather.climacell_daily', 'humidity') }}%
with
{%if state_attr('weather.climacell_daily', 'forecast').precipitation_type is none %}
preciptation of {{ state_attr('weather.climacell_daily', 'forecast').precipitation_type }}
{%else%}
no precipitation
{%endif%}.
Which shows: Currently -11°, feels like -21.44°. Today 7°/-11° sunny humidity 69% with no precipitation.
for me right now.
If you want to see the old version with a for loop where I explain each part of the loop then expand this:
Explination of the loop I previously used
The raw code
{% set thetemp = state_attr('weather.climacell_hourly', 'forecast') %}
{% set hightemp = 0 %}
{% set ns = namespace (hightemp = 0) %}
{% for looper in thetemp %}
{% if loop.index0 < 16 %}
{% if looper.temperature > ns.hightemp %}
{% set ns.hightemp = looper.temperature | float %}
{% endif %}
{% endif %}
{% endfor %}
Currently {{state_attr('weather.climacell_nowcast','temperature')}}°, feels like {{states('sensor.climacell_feels_like')}}°. Today {{ns.hightemp}}°/{{ state_attr('weather.climacell_daily', 'forecast')[0].templow }}° {{ states('weather.climacell_daily') }} humidity {{ state_attr('weather.climacell_daily', 'humidity') }}% with {%if state_attr('weather.climacell_daily', 'forecast').precipitation_type is none %}preciptation of {{ state_attr('weather.climacell_daily', 'forecast').precipitation_type }}{%else%}no precipitation{%endif%}.
Whatâs with that for loop?
Getting the low temp for the day was easy, I just got the low forecasted for tomorrow, which will probably be during the night and is good enough for me.
However, I couldnât find a daily high temperature prediction in the Accuweather or ClimaCell integrations. So I loop through the hourly forecast and find the biggest number!
Lets walk through it.
Put your weather attribute weather.climacell_hourly
into a variable called thetemp
{% set thetemp = state_attr('weather.climacell_hourly', 'forecast') %}
Create a new variable called hightemp
to hold the highest temperature found in the upcoming loop.
{% set hightemp = 0 %}
This is where the comes in. Jinja by default does not allow you to pass variables in and out of loops. Also known as, changing scopes. To allow this you need to use a namespace object which is what is done here.
Check out Reza Rahimiâs great explanation here: python - How can i access a jinja2 variable outside the for loop? - Stack Overflow
Basically, weâre just moving the variable hightemp
into a new variable called ns.hightemp
that is accessible in and out of the loop.
{% set ns = namespace (hightemp = 0) %}
Next is the floor loop with an if statement inside.
{% for looper in thetemp %}
{% if looper.temperature > ns.hightemp %}
{% set ns.hightemp = looper.temperature | float %}
{% endif %}
{% endfor %}
Letâs start with the for loop. This just loops through each hour in the hourly forecast.
{% for looper in thetemp %}
{% endfor %}
Next look at the first if statement.
This limits our loop to the first 16 options. This way we donât look for the whole 24 hour period, and only look at the next 16 hours when we will be awake.
{% if loop.index0 < 16 %}
{% endif %}
Next look at the second if statement.
This checks the temperature sub-attribute of weather.climacell_hourly
. Go to the bottom to see my explanation on sub-attributes.
This if statement compares the temperature of every sub-attribute that we loop through to our variable ns.hightemp
{% if looper.temperature > ns.hightemp %}
{% endif %}
Lastly, when the if statement is true (meaning the forecasted temperature for that hour that the loop is on is greater than the item in ns.hightemp
variable) then we put that hourâs temperature into the variable ns.hightemp
with set ns.hightemp = looper.temperature
. That is followed by | float
because the number in the looper.temperature
could be a decimal number like -10.5 so the | float
ensures the number stays a decimal number.
{% set ns.hightemp = looper.temperature | float %}
Whoa! All that just to find the high temperature for the day!
Yes, now we can talk about the actual notification.
The Notification
The notification template below will say:
Currently 0°, feels like -11.2°. Today 11.0°/-5° partlycloudy humidity 62% with no precipitation.
Below is what makes the notification happen. If you look closely youâll see another if statement at the end. This is because when state_attr('weather.climacell_daily', 'forecast').precipitation_type
is none it it actually just returns nothing, so there will be no words in the notification. This if statement make it so that when it is none then the notification says âno precipitationâ
Currently {{state_attr('weather.climacell_nowcast','temperature')}}°, feels like {{states('sensor.climacell_feels_like')}}°. Today {{ns.hightemp}}°/{{ state_attr('weather.climacell_daily', 'forecast')[0].templow }}° {{ states('weather.climacell_daily') }} humidity {{ state_attr('weather.climacell_daily', 'humidity') }}% with {%if state_attr('weather.climacell_daily', 'forecast').precipitation_type is none %}preciptation of {{ state_attr('weather.climacell_daily', 'forecast').precipitation_type }}{%else%}no precipitation{%endif%}.
A more readable format of the above:
Currently {{state_attr('weather.climacell_nowcast','temperature')}}°,
feels like {{states('sensor.climacell_feels_like')}}°.
Today {{ns.hightemp}}°/{{ state_attr('weather.climacell_daily', 'forecast')[0].templow }}°
{{ states('weather.climacell_daily') }}
humidity {{ state_attr('weather.climacell_daily', 'humidity') }}%
with
{%if state_attr('weather.climacell_daily', 'forecast').precipitation_type is none %}
preciptation of {{ state_attr('weather.climacell_daily', 'forecast').precipitation_type }}
{%else%}
no precipitation
{%endif%}.
The Notification Action
I originally had the trigger be when the iPhone is unplugged in the morning, but the update frequency for the Home Assistant Companion App is pretty slow (>15 minutes) when I tested, unless you have the app open in the foreground.
Wrapping it all up into one automation you getâŠ
alias: 'Notification: Wife Wakeup Weather'
description: >-
Send Wife's phone a custom weather message in
the morning.
trigger:
- platform: time
at: '07:00:00'
condition:
- condition: state
entity_id: person.wife
state: home
action:
- service: notify.mobile_app_wife_iphone
data:
title: Your Daily Forecast
message: >-
{% set thetemp = state_attr('weather.climacell_hourly', 'forecast') %}
{% set hightemp = 0 %}
{% set ns = namespace (hightemp = 0) %}
{% for looper in thetemp %}
{% if loop.index0 < 12 %}
{% if looper.temperature > ns.hightemp %}
{% set ns.hightemp = looper.temperature | float %}
{% endif %}
{% endif %}
{% endfor %}
Currently {{state_attr('weather.climacell_nowcast','temperature')}}°, feels like {states('sensor.climacell_feels_like')}}°. Today {{ns.hightemp}}°/{{ state_attr('weather.climacell_daily', 'forecast')[0].templow }}° {{ states('weather.climacell_daily') }} humidity {{ state_attr('weather.climacell_daily', 'humidity') }}% with {%if state_attr('weather.climacell_daily', 'forecast').precipitation_type is none %}preciptation of {{ state_attr('weather.climacell_daily', 'forecast').precipitation_type }}{%else%}no precipitation{%endif%}.
mode: single
END OF OLD VERSION WITH LOOP EXPLINATION
Below is what makes the notification happen. If you look closely youâll see another if statement at the end. This is because when state_attr('weather.climacell_daily', 'forecast').precipitation_type
is none it it actually just returns nothing, so there will be no words in the notification. This if statement make it so that when it is none then the notification says âno precipitationâ
Currently {{state_attr('weather.climacell_nowcast','temperature')}}°, feels like {{states('sensor.climacell_feels_like')}}°. Today {{ (state_attr('weather.climacell_hourly', 'forecast') | map(attribute="temperature") | list)[0:16] | max }}°/{{ state_attr('weather.climacell_daily', 'forecast')[0].templow }}° {{ states('weather.climacell_daily') }} humidity {{ state_attr('weather.climacell_daily', 'humidity') }}% with {%if state_attr('weather.climacell_daily', 'forecast').precipitation_type is none %}preciptation of {{ state_attr('weather.climacell_daily', 'forecast').precipitation_type }}{%else%}no precipitation{%endif%}.
The Notification Action
I originally had the trigger be when the iPhone is unplugged in the morning, but the update frequency for the Home Assistant Companion App is pretty slow (>15 minutes) when I tested, unless you have the app open in the foreground.
Wrapping it all up into one automation you getâŠ
alias: 'Notification: Wife Wakeup Weather'
description: >-
Send Wife's phone a custom weather message in
the morning.
trigger:
- platform: time
at: '07:00:00'
condition:
- condition: state
entity_id: person.wife
state: home
action:
- service: notify.mobile_app_wife_iphone
data:
title: Your Daily Forecast
message: >-
Currently {{state_attr('weather.climacell_nowcast','temperature')}}°, feels like {{states('sensor.climacell_feels_like')}}°. Today {{ (state_attr('weather.climacell_hourly', 'forecast') | map(attribute="temperature") | list)[0:16] | max }}°/{{ state_attr('weather.climacell_daily', 'forecast')[0].templow }}° {{ states('weather.climacell_daily') }} humidity {{ state_attr('weather.climacell_daily', 'humidity') }}% with {%if state_attr('weather.climacell_daily', 'forecast').precipitation_type is none %}preciptation of {{ state_attr('weather.climacell_daily', 'forecast').precipitation_type }}{%else%}no precipitation{%endif%}.
mode: single
weather.climacell_hourly
sub-attribute explanation
I donât know if âsub-attributeâ is the right word, but thatâs what Iâll use until someone corrects me in the comments.
See how weather.climacell_hourly
has a bunch of data under forecast
attribute? See how it is repeating? You can access those like this: {{ state_attr('weather.climacell_hourly','forecast')[0].temperature }}
This returns the first [0]
(because an index starts at 0) set of sub-attributes for forecast, then .temperature
gives you only the temperature of that first sub-attribute. So in my case it returns -4
(thatâs Fahrenheit by the way).
With this knowledge you can access any hourâs attributes.