Transitioning to new forecast design: Automation condition templates?

2023.9 introduces a change in how forecasts are accessed and begins the deprecation of the .forecast attribute.

However, the change notes do not make it clear what I need to do to modify all my existing uses to the new approach.

In particular, I have several automations that use templates in the conditions to evaluate the forecast. For example, when determining whether to turn on the heat (from a trigger on interior temperature) we check if the high temperature in the forecast is below 76F: {{ (state_attr('weather.klvk_hourly', 'forecast') | map(attribute='temperature') | list) | max < 76 }}

How do I replicate this condition template using the new approach? I presume I won’t be calling a service in the condition template as that would be an asynchronous process.

From the few discussions I’ve been able to find on the topic, it seems like I need to set up some other thing to poll the weather API which then makes the data available to evaluate in a condition template. But exactly what that is or how it works remains unclear to me.

Is that a “Helper - Template Sensor”? Can it be configured through the UI or can it only be done via a YAML file?

Refer to the following example of a Trigger-based Template Sensor that periodically gets the weather forecast.

Your Template Condition would simply reference the Template Sensor as opposed to your Weather entity.

template:
  - trigger:
      - platform: time_pattern
        hours: /1
    action:
      - service: weather.get_forecast
        data:
          type: hourly
        target:
          entity_id: weather.klvk_hourly
        response_variable: hourly
    sensor:
      - name: KLVK Hourly
        unique_id: weather_forecast_klvk_hourly
        state: "{{ now().isoformat() }}"
        attributes:
          forecast: "{{ hourly.forecast }}"

Template Condition:

{{ (state_attr('sensor.klvk_hourly', 'forecast') | map(attribute='temperature') | list) | max < 76 }}

NOTE

You have until March 2024 to implement the changes.


EDIT

Be advised that in the example above, the service call weather.get_forecast (singular) has been deprecated and is now weather.get_forecasts (plural) which can report forecast data for multiple weather entities.

Here’s the revised example:

template:
  - trigger:
      - platform: time_pattern
        hours: /1
    action:
      - service: weather.get_forecasts
        data:
          type: hourly
        target:
          entity_id: weather.klvk_hourly
        response_variable: hourly
    sensor:
      - name: KLVK Hourly
        unique_id: weather_forecast_klvk_hourly
        state: "{{ now().isoformat() }}"
        attributes:
          forecast: "{{ hourly['weather.klvk_hourly'].forecast }}"
3 Likes

No, it requires a Trigger-based template sensor which is not supported in the UI Template helper and must be set up in YAML.

You wouldn’t call the service in the condition, but if you don’t want to set up Template sensors, you can call the service in your action block then follow that with your Template condition.

FWIW, the service does not poll the API, it pulls the data from the integration cache. The integration’s themselves control polling their respective APIs.

Alright, I think I’ve got it working (had to update a bunch of automations which was an unwelcome pain. Thanks for the help.

For anyone finding this thread looking for more details:

I used the “File Editor” add-on to edit /config/configuration.yaml in which I already had a template entry in, so I needed to add the suggested trigger template to it (I really hate YAML, I find it to have a wholly unintuitive syntax; and I say this as someone that loves Python and have no problem with syntactically meaningful whitespace).

Once edited, I saved the file. Then I reloaded the template entities using the Developer Tools -> YAML -> Template Entities reload button. Now you have to wait for the top of the hour for the forecast to get populated.

Alternatively, you can temporarily add another trigger to get it to populate sooner (I also added a trigger for startup to ensure it’s available and up to date after a reboot):

- trigger:
  - platform: time_pattern
    hours: /1
  - platform: homeassistant
    event: start
  - platform: time
    at: "11:35:00"

The thing bugging me the most is that HA implicitly generates an entity ID from the name (and seems to ignore unique_id? I find this bizarre and annoying). So it wasn’t clear to me why the template condition referred to sensor.klvk_hourly, but that’s the entity_id that HA generates from the Sensor: Name of “KLVK Hourly”.

Also, it’s not clear why we can’t put the forecast into the state property of the sensor, but when I tried that it didn’t seem to do what I wanted.

A bit annoying that they deprecated something without a UI-supported approach to restore the desired outcome.

1 Like

You’re welcome!

Please consider marking my post above with the Solution tag. It will automatically place a check-mark next to the topic’s title which signals to other users that this topic has been resolved. This helps users find answers to similar questions.

For more information about the Solution tag, refer to guideline 21 in the FAQ.


Correct.

If you refer to my example above, the Template Condition references the Trigger-based Template Sensor using sensor.klvk_hourly (not sensor.weather_forecast_klvk_hourly).

In that entity’s configuration, the value of name is used to create the new entity’s entity_id and the value of unique_id is used internally (in the entity registry) to uniquely identify the entity.

In reading the [2023.12] blog, it is saying that HA is also deprecating get_forecast and replacing it with get_forecasts (plural) and with it the response/format is different. So I’m trying it out:

get_forecast returns:

forecast:
  - detailed_description: >-
      Meteorologist Elizabeth Gardner here on this chilly day! Mostly sunny
      skies and still very cool with some frost possible this morning with a
      light freeze. Later this afternoon it should be a touch milder than what
      we had on Wednesday with highs in the lower-mid 50s.For the night: Partly
      cloudy and still cold with lows in the lower-mid 30s.
    wind_bearing: 270
    precipitation_probability: 0
    datetime: "2023-12-07T06:00:00-05:00"
    condition: partlycloudy
    temperature: 54
    templow: 35
    wind_speed: 7
  - detailed_description: >-
      Partly to mostly cloudy skies blah blah

get_forecasts (plural) returns:

weather.my_abc_weather:
  forecast:
    - detailed_description: >-
        Meteorologist Elizabeth Gardner here on this chilly day! Mostly sunny
        skies and still very cool with some frost possible this morning with a
        light freeze. Later this afternoon it should be a touch milder than what
        we had on Wednesday with highs in the lower-mid 50s.For the night:
        Partly cloudy and still cold with lows in the lower-mid 30s.
      wind_bearing: 270
      precipitation_probability: 0
      datetime: "2023-12-07T06:00:00-05:00"
      condition: partlycloudy
      temperature: 54
      templow: 35
      wind_speed: 7
    - detailed_description: >-
        Partly to mostly cloudy skies blah blah

Note: weather.my_abc_weather is the target weather entity id I’m getting the forecasts from.

My current template sensor’s attribute config:
forecast: "{{ daily_response_is.forecast }}"
of course doesn’t work with the new format.

For the new format I got the following to work:
forecast: "{{ daily_response_is['weather.my_abc_weather'].forecast }}"

I would like to separate the daily values because I use them for automations, e.g. temperature_low or condition.

Since the entity is the first value in the new get_forecasts action, how can I define the path to temperature of the first day?

weather.xxxxx:
  forecast:
    - datetime: "2024-04-07T00:00:00Z"
      condition: cloudy
      wind_bearing: SO
      wind_gust_speed: 16.7
      uv_index: 4
      precipitation_probability: 2
      temperature: 18
      templow: 18
      wind_speed: 2.58
      precipitation: 0

The old path in my config was

      - name: "DWD_xxx_Condition_0d"
        state: "{{ forecast.forecast[0].condition }}"

Sorry, I may not completely understand your question and configs, but if you have created a trigger based template sensor as shown above say for daily forecast (in my case mine is called sensor.weather_forecast_daily), then the following seems to work in dev tools->template:

To get all the current day’s forecasted data:

{{ (state_attr('sensor.weather_forecast_daily', 'forecast'))[0] }}

and then more specific like condition, or temp low

{{ (state_attr('sensor.weather_forecast_daily', 'forecast'))[0].condition }}
{{ (state_attr('sensor.weather_forecast_daily', 'forecast'))[0].templow }}

Thanks for your info.

I got one sensor to work for me but struggling to add the rest. The first code below are the sensors I had configured before the breaking change (which I missed in the notes).

The template trigger is what I have added, but I’m unable to add the others.
Any help would be appreciated.

This is my original code

      - name: Met_no Tomorrows Forecast
        state_class: "measurement"
        device_class: "temperature"
        unit_of_measurement: '°C'
        state: "{{ state_attr('weather.forecast_home', 'forecast')[1]. temperature }}"
      - name: Met_no 2 Days Ahead Forecast
        state_class: "measurement"
        device_class: "temperature"
        unit_of_measurement: '°C'
        state: "{{ state_attr('weather.forecast_home', 'forecast')[2]. temperature }}"
      - name: Met_no 3 Days Ahead Forecast
        state_class: "measurement"
        device_class: "temperature"
        unit_of_measurement: '°C'
        state: "{{ state_attr('weather.forecast_home', 'forecast')[3]. temperature }}"
      - name: Met_no Tomorrows Low Forecast
        state_class: "measurement"
        device_class: "temperature"
        unit_of_measurement: '°C'
        state: "{{ state_attr('weather.forecast_home', 'forecast')[1]. templow }}"
      - name: Met_no 2 Days Ahead Low Forecast
        state_class: "measurement"
        device_class: "temperature"
        unit_of_measurement: '°C'
        state: "{{ state_attr('weather.forecast_home', 'forecast')[2]. templow }}"
      - name: Met_no 3 Days Ahead Low Forecast
        state_class: "measurement"
        device_class: "temperature"
        unit_of_measurement: '°C'
        state: "{{ state_attr('weather.forecast_home', 'forecast')[3]. templow }}"
_________________________________________________________________________
This is the new template trigger that I have added

template:
  - trigger:
      - platform: time_pattern
        hours: /1
  - platform: homeassistant
    event: start
  - platform: time
    at: "22:20:00"
    action:
      service: weather.get_forecasts
      data:
        type: hourly
      target:
        entity_id: weather.forecast_home
      response_variable: forecast_data
    sensor:
      name: Met_no Tomorrows Forecast1
      state: "{{ forecast_data['weather.forecast_home'].forecast[1].temperature }}"
      attributes:
        forecast: "{{ forecast_data['weather.forecast_home'].forecast }}"
        updatedAt: "{{ now().isoformat() }}"

Do you mean something like the following:

template:
  - trigger:
      - platform: time_pattern
        hours: /1
      - platform: homeassistant
        event: start
      - platform: time
        at: "22:20:00"
    action:
      service: weather.get_forecasts
      data:
        type: hourly
      target:
        entity_id: weather.forecast_home
      response_variable: forecast_data
    sensor:
      - name: Met_no Tomorrows Forecast1
        state: "{{ forecast_data['weather.forecast_home'].forecast[1].temperature }}"
        attributes:
          forecast: "{{ forecast_data['weather.forecast_home'].forecast[1] }}"
          updatedAt: "{{ now().isoformat() }}"
      - name: Met_no 2 Days Ahead Forecast
        state: "{{ forecast_data['weather.forecast_home'].forecast[2].temperature }}"
        attributes:
          forecast: "{{ forecast_data['weather.forecast_home'].forecast[2] }}"
          updatedAt: "{{ now().isoformat() }}"

Thank you. This is exactly what i was looking for`

I don’t get it.

What do I have to do?

This worked before:

template:
  - sensor:
      - name: "Vorhersage Temperatur"
        unique_id: vorhersage_temperatur
        unit_of_measurement: "°C"
        device_class: temperature
        state: "{{ state_attr('weather.local','forecast')[0].temperature }}"

Change your existing Template Sensor into a Trigger-based Template Sensor using the example shown in the Weather integration’s documentation:


The following example is a combination of the one in the documentation and the configuration of your Template Sensor.

template:
  - trigger:
      - platform: time_pattern
        hours: /1
      - platform: event
        event_type: event_template_reloaded
    action:
      - service: weather.get_forecasts
        data:
          type: hourly
        target:
          entity_id: weather.local
        response_variable: hourly
    sensor:
      - name: "Vorhersage Temperatur"
        unique_id: vorhersage_temperatur
        unit_of_measurement: "°C"
        device_class: temperature
        state: "{{ hourly['weather.local'].forecast[0].temperature }}"

EDIT

Here’s a slightly fancier version that lets you define the Weather entity in one place (instead of two).

template:
  - trigger:
      - platform: time_pattern
        hours: /1
      - platform: event
        event_type: event_template_reloaded
    action:
      - variables:
          w: weather.local
      - service: weather.get_forecasts
        data:
          type: hourly
        target:
          entity_id: '{{ w }}'
        response_variable: hourly
    sensor:
      - name: "Vorhersage Temperatur"
        unique_id: vorhersage_temperatur
        unit_of_measurement: "°C"
        device_class: temperature
        state: "{{ hourly[w].forecast[0].temperature }}"
1 Like

Thanks a lot. I must have had some sort of typo in my adaptation.