Rain forecast automation

Tags: #<Tag:0x00007fc4146aa718> #<Tag:0x00007fc4146a9ca0>

Hi there!

I’m trying to set an automation that takes the forecast from Met.no to detect if there is rain forecasted for the next 4 days, but so far I had no luck. In the future I intend to set an electric outlet at the washing machine so this automation will trigger when the laundry is done and so I will know if I need to use the dryer or I can hang the clothes out to be dryed outdoors.

- id: '1606345692704'
  alias: Rain alert
  description: ''
  - platform: state
    entity_id: weather.my_home
    attribute: forecast
    to: rainy
  condition: []
  - service: notify.telegram
      title: '*RAIN*'
      message: The forecast shows rain for the nex days.
  mode: single

Open up developer tools, and click the ‘states’ tab.

Find the weather.my_home and take a look there. Specifically, look at the ‘forecast’ attribute.

From here, it might make more sense what you need to look at.

I don’t have met.no, but it is likely that ‘forecast’ is actually a list of things…each entry being a new day. I highly doubt the forecast section has a single value in it where it is sunny/rainy, etc. There is probably temperatures, highs, lows, etc.

If the forecast is a list, and in that list there is a value called ‘condition’, you ‘might’ be able to do

attribute: "forecast[0].condition"

however, I’m not sure. I have a feeling that wont work…but you can give it a shot. What will work is this:

  - platform: template
    value_template: "{{ state_attr('weather.my_home', 'forecast')[0].condition == 'rainy' }}"

Again, this assumes that forecast is a list, and the first in the list is the next day, and there is a value called ‘condition’ from that list…and that value can be set to ‘rainy’.

So, yeah. Look in the dev tools and see what kind of things you might have.

Thanks Jim!

That’s exactly what I did, I looked into the weather entity at the developers tools to see the states that the weather entity could show. But I do not know how can I state the arguments for the automation so that will look up to the rain forecast in the nex 4 days, not only the first one. I guess that is the [0] part of your code? (forecast[0].condition)

This is what the developers tools is showing for the weather entity:

temperature: 9
humidity: 91
pressure: 1013
wind_bearing: 127.5
wind_speed: 15.5
attribution: >-
  Weather forecast from met.no, delivered by the Norwegian Meteorological
  - condition: cloudy
    precipitation: 0.4
    temperature: 12.5
    templow: 7.1
    datetime: '2020-11-27T11:00:00+00:00'
    wind_bearing: 46.1
    wind_speed: 18
  - condition: partlycloudy
    temperature: 12.7
    templow: 6.9
    datetime: '2020-11-28T11:00:00+00:00'
    wind_bearing: 44.8
    wind_speed: 12.6
  - condition: cloudy
    temperature: 10.7
    templow: 3.5
    datetime: '2020-11-29T11:00:00+00:00'
    wind_bearing: 63.2
    wind_speed: 6.5
  - condition: partlycloudy
    temperature: 12
    templow: 3.5
    datetime: '2020-11-30T11:00:00+00:00'
    wind_bearing: 200.3
    wind_speed: 8.3
  - condition: sunny
    temperature: 11.3
    templow: 1.5
    datetime: '2020-12-01T11:00:00+00:00'
    wind_bearing: 157.9
    wind_speed: 5.8
friendly_name: My home


Yep. That is a YAML list, so…like most lists, you need to specify the index you want. Each group of things between the ‘-’ character is an element, so forecast[0] would be the first one, forecast[1] the seconds, etc.

If you want to look at multiple days, you’ll have to do some more magic.

The easiest is to just use that index for the day. So if you wanted tomorrow, you’d use forecast[1].

  platform: template
  value_template: "{{ {{ 'rainy' in [forecast[0].condition, forecast[1].condition] }}"

(see **Note at the end of this post)

Finally, there are the magic jinja2 filter commands that are 100% voodoo magic and only took me an entire year to even begin to understand.

I truly don’t expect these to make sense to anyone just learning YAML/JINJA2, but here are some examples. My 2 favorite jinja2 filters are ‘selectattr’ and ‘map’.

{{ state_attr('weather.home', 'forecast')[:4] | selectattr('condition', 'eq', 'rainy') | list | count }}

That one takes the up to the first 4 elements ([:4]) in the forecast list and uses the selectattr filter to basically “extract all entries from the list that match this condition”. In my example, the condition is “any condition that is equal to rainy”. This returns an ‘object’, so I use the | list command to convert the object to a list, then | count to count how many there are. Essentially, this will just count how many days are going to be rainy.

{{ state_attr('weather.home', 'forecast')[:4] | map(attribute='condition') | list}}

This one uses the ‘map’ filter to create a group of things from the forecast based on what I say. So, this will return a list of JUST the conditions. Again, I use ‘list’ to convert it to a list.

['sunny', 'sunny', 'partlycloudy', 'partlycloudy']

Putting it all together, we can create the following automation.

- alias: Gonna Rain
    # Change this to the number of days in the future you want to look. 
    days: 4
    # See Note below for time trigger reason
    platform: time
    at: "05:00:00"
    - "{{ 'rainy' in state_attr('weather.home', 'forecast')[:days] | map(attribute='condition') }}"
    - service: notify.notify
        title: "It's gonna rain"
        message: "Forecast shows rain in the next {{days}} days"

**Note: I decided to run this at a certain time rather than triggering on the forecast. Reason is, you probably don’t want to do something EVERY SINGLE TIME the forecast gets updated. For example, if you send a notification if it’s going to rain, you’d get a notification every time it shows rain in the forecast, even if it updates only the current temperature.

1 Like

WOW! That looks lik witchcraft to me! I can understand each step you explained, but when you put it together, I’m lost. I have been triying to learn jinja2 since this past summer, but it’s like reading chinese to me…I’m a lawyer so I’m REAAAAALY far from my area of expertise.

I run your code, changing the condition to partially cloudy because there was no rain forecasted for the next days, but it does not trigger. Also, the log doesn’t show any errors, so there is nothing wrong with the code. Any thoughts?

- id: '1606432746526'
  alias: Rain alert
  description: ''
  - platform: time
    at: 00:38:00
  - condition: template
    value_template: '"{{ ''cloudy'' in state_attr(''weather.my_home'', ''forecast'')[:days]
      | map(attribute=''condition'') }}"'
  - service: notify.telegram
      title: '*RAIN*'
      message: "The forecast shows rain for the nex {{days}} days"
    days: 4
  mode: single

Silly question, but did you wait until 12:38 AM? That’s the only time it will fire.

You can open dev tools, click on templates, and you can paste that template right into the window. It should output True or False if it worked and also show the 4 day’s conditions.

{% set days = 4 %}
{{ ''cloudy'' in state_attr(''weather.my_home'', ''forecast'')[:days]  | map(attribute=''condition'') }}
{{ state_attr(''weather.my_home'', ''forecast'')[:days]  | map(attribute=''condition'') | list }}

Yes, of course! I tried tweaking it a few times changing the condition from rainy to cloudy and partially cloudy and putting [4] instead of [:days] and did not trigger, and every time I tried the template I changed the time of the trigger for a few mitutes ahead, so the system had time to record the changes.

When I paste the code in the developers tools it detects a coding error: “TemplateSyntaxError: expected token ‘end of print statement’, got ‘cloudy’”

I really appreciate your help!

This is an unfortunate effect of using the GUI for yaml. For some reason, it puts everything in single quotes, then used double single quotes where a single quote would be needed.

The template editor doesn’t like these quotes. So replace all instances of double single quotes with single quotes.

{% set days = 4 %}
{{ state_attr('weather.my_home', 'forecast')[:days]  | map(attribute='condition') }}
{{ 'sunny' in state_attr('weather.home', 'forecast')[:days]  | map(attribute='condition') }}

Also, if you’re using the automation editor, don’t put the outside quotes on it. It will add its own single quote to the front of it to be annoying.

 # In GUI, input it this way without the outside quotes.
 value_template: {{ 'cloudy' in state_attr('weather.my_home', 'forecast')[:days]  | map(attribute='condition') }}

Yesssss!! That did the trick. The syntax error was in the condition because of the quotes, as you said. Works like a charm now! Really appreciate it.

Is there a tutorial or documentation you would recommend to start from scratch on jinja2? I really would like to learn it.

I’ve learned everything through google lol.

I use the template editor a ton to try things out, and open that jinja2 website and see what things do. But even then it’s super confusing.

I used this post a ton with learning different things that could be done. Just trying out the different things in the template editor and modifying things to see what would output, etc.

Also I learn a lot by helping people here. I usually have some janky solution and someone else comes along and says “you can do that 1000 line jank in 2 lines like this”. I think I’m now at the point where I’m the one giving the 2 line solutions these days. Only took me a year!

1 Like

This automation has been working like a charm for weeks now, but I realized that I need the variable of 4 days to be more specific. I need to calculate the remaining days untill next wednesday so the automation will check the forecast from today untill next wednesday and tell me if it’s gonna rain. I’ve been looking in the forum for the template to calculate the remaining days untill a specific week date and convert it on an integral number with the format %w, but I cant seem to tweak a template that works. Can you please help with this code?

    # now().weekday() returns 0 for monday, 1 for tuesday, 2 for wednesday, etc. 
    # Subtract wednesday from today. Then modulo to handle wrap around. 
    days: "{{ (2 - now().weekday()) % 7 }}"

Keep in mind this will return 0 on wednesday itself. If you want wednesday to return 7 for next week, do this

days: >
  {% set num_days = 2 - now().weekday()%}
  {{ num_days if num_days > 0 else (7 - num_days | abs) }}

That one will be a number between 7 and 1.

1 Like

Seems to work flawlessly! Thanks a lot Jim!!

1 Like

Hi @Amaia_Espejo and @jocnnor. This is very helpful and inspirational thread. Thank you!
My weather data provider (FMI) has similar kind of data in developer tools. What I’m trying to figure out how could I refer to or get a single forecast item, like first condition or second temperature. Most likely an easy nut to crack, but I just can’t figure it out…

Hi @AriK !. Sorry but my Jinja2 skills are still very very limited and I also can’t make it work. I’ve been triying to twich it for a wile to get the temperature forecast two days from now without success.

Hi @Amaia_Espejo! I feel for you! Let’s hope that someone more skilled in Jinja2 will help us out :slight_smile:

Good news @Amaia_Espejo!

A friend gave a hint that this might work:

{{ state_attr('weather.hakametsa', 'forecast')[0].temperature }}

…and it did! Hopefully it helps you, too :slight_smile:

1 Like

Thanks for the tip!

@Amaia_Espejo, you might also want to take a look at this post, which will help me forward:

I’m trying to write a script that does this but am having a hard time translating this knowledge/formatting into that use. Particularly the condition stuff. I basically want to be able to call a script (via an Alexa routine in this case) that sends notification if there is rain in the forecast for the next day. Any help would be appreciated.