Automation condition based on weather forecast for the next day

Hi,

I’m struggling here a bit with using automation condition that tests a state of a list item attribute based on Met.no weather forecast integration.

The goal is simple - turn on the garden sprinkler only if it’s not forecasted to rain the next day.

I’ve done some template debugging in the Developer Tools and it all seems to work well there, but whatever I try I can’t make it work as an automation condition.

These are the state attributes for my weather.home entity:

temperature: 22.7
humidity: 52
pressure: 1018.5
wind_bearing: 128.6
wind_speed: 2.9
forecast:
  - condition: partlycloudy
    precipitation: 0.4
    temperature: 23.5
    templow: 11
    datetime: '2022-06-16T11:00:00+00:00'
    wind_bearing: 176
    wind_speed: 12.2
  - condition: sunny
    precipitation: 0
    temperature: 26.3
    templow: 13
    datetime: '2022-06-17T11:00:00+00:00'
    wind_bearing: 197.7
    wind_speed: 20.5
  - condition: cloudy
    precipitation: 3
    temperature: 27.2
    templow: 17.5
    datetime: '2022-06-18T11:00:00+00:00'
    wind_bearing: 64
    wind_speed: 23
  - condition: partlycloudy
    precipitation: 6.2
    temperature: 15.9
    templow: 10.9
    datetime: '2022-06-19T11:00:00+00:00'
    wind_bearing: 42.5
    wind_speed: 26.3
  - condition: partlycloudy
    precipitation: 0
    temperature: 19.3
    templow: 11.8
    datetime: '2022-06-20T11:00:00+00:00'
    wind_bearing: 56.5
    wind_speed: 18
attribution: >-
  Weather forecast from met.no, delivered by the Norwegian Meteorological
  Institute.

If I use State type automation condition for the current day using just the entity’s state, everything works fine:

condition: state
entity_id: weather.home
state: sunny

If I however want to use tomorrow or any subsequent days, I can’t make it work, whatever I use getting into lists and their attributes.


I’ve tested this template in Developer Tools for tomorrow’s forecast. It correctly returns true:

{{ state_attr('weather.home', 'forecast')[0].condition != 'rainy' }}

If I try to use the same template in the Automation Condition type Template:

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

I receive the error:
template value should be a string for dictionary value @ data[‘value_template’]. Got None
With or without double quotes, I’ve tried various brackets at various places, it never works.


I’ve also tested these two templates in Developer Tools for tomorrow’s forecast. Both correctly return partlycloudy :

{{ states.weather.home.attributes.forecast[0].condition }}
{{ state_attr('weather.home','forecast')[0].condition }}

If I try to use State type condition with the list attribute as:

condition: state
entity_id: weather.home
attribute: forecast[0].condition
state: 'partlycloudy'

It always returns false, despite that list index state being 'partlycloudy'

Any ideas what I’m doing wrong?

Thanks

1 Like

Just maybe, condition is a reserved word in the automation system. Try:

value_template: "{{ state_attr('weather.home','forecast')[0]['condition'] != 'rainy' }}"

If that doesn’t fix it, please post your entire automation code.

I saw this video the other day in which he does a similar thing using openweather maybe it will help.

1 Like

Thanks for the reply. The fix didn’t work, same error.

The automation is fairly simple at the moment, I’ve got stuck fairly early, so I don’t think it’s relevant in this case. It’s already when I test the condition on its own I can see it doesn’t work.

But here it is anyway:

alias: Water Lawn
description: ''
trigger:
  - platform: sun
    event: sunrise
    offset: '01:15'
  - platform: sun
    event: sunset
    offset: '-1:30'
condition:
  - condition: template
    value_template: >-
      "{{ state_attr('weather.home','forecast')[0].condition !=
      'rainy' }}"
action:
  - service: switch.turn_on
    target:
      entity_id: switch.rear_garden_tap
    data: {}
mode: single

This works (for today):

condition:
  - condition: state
    entity_id: weather.home
    state: partlycloudy

This doesn’t (for tomorrow):

condition:
  - condition: state
    entity_id: weather.home
    state: partlycloudy
    attribute: forecast[0].condition

Try to remove the “” from your template, as it isn’t in the same line as value_template.

Like this:


condition:
  - condition: template
    value_template: >-
      {{ state_attr('weather.home','forecast')[0].condition != 'rainy' }}

Thanks for reply. As I’ve said, I’ve tried various combinations of various quotes and their placement (including your suggestion), always the same error.

If I create a simple template sensor:

template:
  - sensor:
      - name: "Forecast Tomorrow"
        state: "{{ state_attr('weather.home','forecast')[0].condition }}"

and then test the state of this new sensor:

condition: not
conditions:
  - condition: state
    entity_id: sensor.forecast_tomorrow
    state: rainy

everything works fine.

It’s just digging deeper into attribute list directly in the condition type template that doesn’t work.

Nice inspiration for more complex future setup, thanks!

I’ve tried this and although it reports an error when I test on the Automation dialog, just like all condition based on templates, it works properly:

condition: template
value_template: '{{ state_attr(''weather.smhi_home'',''forecast'')[1].condition == ''sunny'' }}'

In my case the index 0 on forecast is today, so I’ve used 1 for tomorrow.

Very interesting.

I’ve experimented with this now as well.

If I use this template as Automation / Conditions it doesn’t test when created (produces an error), is always ignored in the trace when triggered and because of that the Automation runs and action gets always performed, regardless of this condition.

If I use this template as Automation / Actions / Condition I can’t test it (no test button), but when I trigger the automation, it tests the template condition correctly first and only performs Action if it returns true.

In the Conditions section of Automation definition it says:
Conditions are optional and will prevent the automation from running unless all conditions are satisfied.
Yet when defined, the condition is not tested (manual test produces an error), result is ignored and the automation runs anyway.

If I define the exact same Condition as first action in the Actions section instead , there it gets tested correctly and further Actions stopped if it tests false.

Now that is quite confusing for me and I don’t really understand the reasons why that would be the case.

EDIT: When the Automation gets triggered rather than simply run, it actually tests the Conditions section as it should and the template works, despite the error during test.

Oh well, bug I guess. Now I have to build testing automation with artifical trigger just to test the conditions work and are tested properly as the test doesn’t work.
Btw: If the template is one-liner, it needs double quotes around it. If not, no double quotes needed.

Thanks for all your help.

Not a bug; the behavior is known and documented. See: Testing your automation.

Also documented and it doesn’t have to be double-quotes because it depends on what kind of quotes are used within the template (inner and outer quotes must be different).


If you want to test your automation by manually triggering it and have its condition evaluated, use Developer Tools → Services. Select the “Automation: Trigger” service, select your automation, then disable the “Skip Condition” option before clicking the “Call Service” button.

1 Like

Sorry, probably didn’t make it clear. I consider Test function in the automation visual builder producing an error a bug, not the behaviour of the automation testing process as you’ve kindly reposted here. That one works well, I just didn’t understand it well at first.

If that was your intention then I agree it wasn’t clear. The only hint of the Automation Editor’s Test function is this brief mention in the first paragraph: “If I use this template as Automation / Conditions it doesn’t test when created”. It’s followed by several paragraphs about the behavioral difference between automatic versus manual triggering and concluded by “Oh well, bug I guess”.

  • Yes, the Test function, in its current form, needs improvement because it doesn’t handle some things correctly (bug; reports an error when there isn’t one).
  • No, when manually triggering an automation, skipping its trigger and condition isn’t a bug.

I highly recommend reviewing the links I posted above. It can save you time and frustration when debugging other automations/scripts/templates/etc.

Regarding the State Condition you created employing the attribute option, you supplied it with this:

attribute: forecast[0].condition

Whereas forecast is the name of an attribute in weather.home, the following is not: forecast[0].condition.

That’s an attempt to reference a key within the dictionary in the forecast attribute. That’s something you would do with a template but the State Condition’s attribute option doesn’t support templates.

As you have discovered, you need to use a Template Condition.

1 Like

Thanks for the detailed and patient analysis and description. I appreciate the pointers to the right places as I always learn a lot of new stuff.

HA is immensely powerful and without doubt one of the best solutions for home automation. It is also quite complicated for some specific but simple tasks and so source of endless frustrations for me, usually due to a trivial stuff that takes ages to solve, despite brilliant documentation and active community.

This test function is a prime example. If it just wasn’t there, I would most likely create a test automation first and analyse my routine using the developer tools as advertised. Or as I’d do few months / years ago when it wasn’t there. But because it was there and constantly producing an error, I was desperately trying to feed it something that would pass the check so to speak, without abandoning it altogether earlier. It might sound silly for a seasoned HA user/developer, but for someone looking for quick simple solutions it was the low hanging fruit that turned out to be a bit sour :wink:

Lesson learned.

Nope, not silly at all. I can empathize with your feeling of “there’s goes time I’ll never get back”.

For the longest time, the Automation Editor felt like it was last on every developer’s to-do list. It had limited functionality and got very few enhancements. As a consequence, the “seasoned” users you mentioned, avoided it entirely and used a text editor to compose their automations (like Visual Studio Code with some plugins to guard against syntax errors).

The Automation Editor received many enhancements and is substantially better now than it ever was … yet not without glitches and (still) some limitations. The lying Test button being one of them. :wink:

Did you ever get a working solution? I’m waiting a similar process, where I can take the value for ‘Tomorrow’s Temperature’ and perform automation actions. But cannot seem to work out a way to get the value from the forecast array.

I can get the value via the forecast[0].temperature, like you have for condition, but cannot seem to use it in automation and the custom yaml option doesn’t seem to return options. The weather card can parse the forecast and not sure why it’s can’t be in an accessible array/valueset of day[0], day[1], etc.

For anyone else who ends up here, I learned from the Weather entity docs that some weather implementations (such as WeatherKit) do not provide a forecast attribute, but you can use the weather.get_forecast service to access their forecast.

I ended up doing something like this (I was interested in whether there is rain in the forecast in the next 4 hours):

action:
  - service: weather.get_forecast
    data:
      type: hourly
    target:
      entity_id: weather.home_weatherkit  # replace with your desired weather entity
    response_variable: get_forecast_result
  - if:
      - condition: template
        value_template: >-
          {% set loop_result = namespace(has_rain=false) -%}
          {% for entry in get_forecast_result.forecast -%}
          {%   if now() <= entry.datetime | as_datetime <= now() +
          timedelta(hours=4) -%}
          {%     if entry.precipitation_probability > 0 -%}
          {%       set loop_result.has_rain = True -%}
          {%     endif -%}
          {%   endif -%}
          {% endfor -%}
          {{ loop_result.has_rain }}
    then:
      - ...
    else:
      - ...
1 Like

You can get that result in a single statement without the loop:

value_template: >-
  {{ get_forecast_result['forecast']
     |selectattr('datetime','>=',now().isoformat())
     |selectattr('datetime','<=',(now()+timedelta(hours=4)).isoformat())
     |selectattr('precipitation_probability','>',0)
     |list|count > 0 }}

I’ve split it onto multiple lines for readability but it could be on a single line.

2 Likes

Thanks for the tip. This works, but since it’s comparing strings, the dates need to be in the same time zone. Changing now() to utcnow() made it work for me, since weather.get_forecast seems to return timestamps in UTC.

For the HA 2023.12 update I also saw that weather.get_forecast is deprecated, so changed it to use weather.get_forecasts instead and used get_forecast_results['weather.home_weatherkit']['forecast'] to read the results.

1 Like