New weather forecast template

Because this is way too complicated (seriously - why not just have forecasts as an attribute in the weather sensor??? Forcing a template for basic functionality is ridiculous), and because several of the answers are flat-out broken, here is a working template sensor for daily and hourly forecasts, using Pirateweather:

template:
  - trigger:
    - platform: time_pattern
      hours: "/4"
    - platform: homeassistant
      event: start
    action:
      - service: weather.get_forecasts
        data:
          type: daily
        target:
          entity_id: weather.pirateweather
        response_variable: daily
      - variables:
          today: "{{ daily['weather.pirateweather'].forecast[0] }}"
    sensor:
      - name: Pirateweather Daily Weather Forecast
        unique_id: pirateweather_forecast_daily
        state: "{{ now().isoformat() }}"
        attributes:
          forecast: "{{ daily['weather.pirateweather'].forecast }}"
      - name: "Pirateweather High"
        unique_id: pirateweather_forecasted_high_temp
        state: "{{ today.temperature }}"
        unit_of_measurement: °F
      - name: "Pirateweather Low"
        unique_id: pirateweather_forecasted_low_temp
        state: "{{ today.templow }}"
        unit_of_measurement: °F
      - name: "Pirateweather Rain Chance Today"
        unique_id: pirateweather_forecasted_ran_chance
        state: "{{ today.precipitation_probability }}"
        unit_of_measurement: "%"
  - trigger:
    - platform: time_pattern
      hours: "/1"
    - platform: homeassistant
      event: start
    action:
      - service: weather.get_forecasts
        data:
          type: hourly
        target:
          entity_id: weather.pirateweather
        response_variable: hourly
    sensor:
      - name: Pirateweather Hourly Weather Forecast
        unique_id: pirateweather_forecast_hourly
        state: "{{ now().isoformat() }}"
        attributes:
          forecast: "{{ hourly['weather.pirateweather'].forecast }}"

Most of the other things posted in this thread are missing ['weather.pirateweather'] (or whatever your weather sensor is) as a lookup in the map on the forecast variable, and of course trigger-based templates are effectively impossible to debug outside of trial and error.

I would love to see this as an attribute in the weather domain. Home Assistant updates are supposed to make accessing information easier, not harder. I understand that the Home Assistant project prefers breaking changes to having legacy code stick around, but the fact that something as basic as “is it going to rain in the next 2 hours?” requires multiple nested templates when it used to be relatively straightforward is IMO ridiculous.

15 Likes

The forecast attribute was deliberately removed as part of a general initiative to minimize the use of attributes. Its removal was announced last September (2023).

The examples in this topic are several months old and predate the change of service call (last December) from weather.get_forecast (singular) to weather.get_forecasts (plural). That’s why the older examples use the response_variable without an explicit reference to the weather entity (because it could only contain data for a single weather entity whereas now it can be more than one).

1 Like

I think your reply here just proved my point.

“Several months old” (not even a year, this topic is barely 6 months old at time of posting) and it’s gone through several breaking changes to the point where most of the information is incorrect? And who knows if my reply will even be correct in 2-3 months. The speed of breaking changes is ridiculous.

I’ve been using HASS since 2016, and I even contributed integrations myself (I am the original author of the Todoist integration, way back when). The fact that it’s been 8 years and the speed of breaking changes means I’m still looking up basic things like “how to write a template sensor” (since all my old template sensors broke) is silly. I’m a programmer as well, and I prefer being able to open an IDE and look at everything in one spot rather than having to pick through a bunch of GUI windows.

Removing attributes is something I can get behind… if they are given an easy, built-in, get-it-for-free alternative (e.g. another sensor). Having to make someone write a cryptic template to replace formerly built-in functionality for something as basic as “is it going to rain soon?” is really silly, IMO.

Regardless, this isn’t really the topic for that - I just wanted to provide a working (as of March 2024) template for others, as this page appears near the top of the Google results when someone is looking for how to get Home Assistant to tell you the hourly forecast for use in things like automations.

12 Likes

Two changes; remove attribute, improve service call.

In this particular case, the elimination of the attribute had a grace period of 6 months (ended this month). The service call evolved from handling single to multiple weather entities within the grace period.

Basically, a fairly pedestrian pace for changes and now the older examples in this topic are outdated (the eventual fate of many examples in this forum).

There should be. Check the device in integrations page and enable entities that you want.

An example for this is the accuweather integration. All the forcast information is separated into separate entities.

If that’s not the case for whatever weather integration you’re using, make a feature request for that integration.

The 6 month grace period is both for users and integrations to catch up with whatever the change is. This doesn’t always happen, and in those cases feature requests or issues should be raised.

All the solutions in this thread are band-aides for users to get back the exact same entity they previously had instead of rolling with the changes.

e.g.

1 Like

Alright jumping in on this thread now that 2024.4 is out and the forecast attribute has been removed. I updated a templated weather provider for my use case:

  • Start with a weather entity from the OpenWeather integration
  • Create a template weather entity combining a local sensor with the forecast from OpenWeather
  • Display this new entity in the weather-forecast card

I sorted it out after finding the very helpful debugging thread from @dbs: Debugging templates and service response_variables

template:
  - trigger:
      - platform: time_pattern
        hours: "/4"
      - platform: homeassistant
        event: start
      - platform: event
        event_type: event_template_reloaded
    action:
      - service: weather.get_forecasts
        data:
          type: daily
        target:
          entity_id: weather.daily
        response_variable: daily
    weather:
      name: Local
      temperature_template: "{{ states('sensor.outside_temp') | float(0) }}"
      temperature_unit: "°F"
      humidity_template: "{{ states('sensor.outside_humidity') | float(0) }}"
      condition_template: "{{ states('weather.daily') }}"
      forecast_daily_template: "{{ daily['weather.daily'].forecast }}"

A bit more involved than the previous 8 line template but it works :slight_smile:

Also FWIW, the docs still show the forecast_template option that was removed.

6 Likes

I was unable to call the service weather.get_forecasts for either Accuweather or OpenWeathermap integrations. OpenWeatherMap did support an “hourly” data type. I am now forced to go to a HACS integration Pirate Weather based on code shown above which is working. If the roadmap is to remove attributes that is ok, but the solution to have to create a template sensor in configuration.yaml for Weather forecast is a step backwards and the next release needs to address this.

1 Like

OpenWeather supports different modes so you’d need to add another entry to support that. For example I have 2 OpenWeatherMap integration entries, one using onecall_daily and the other with onecall_hourly. The hourly forecasts are working for me with that hourly integration.

Well, happy it works for you but I ma still struggling :frowning: You code is a great base but I cannot make it work.

template:
  - trigger:
      - platform: time_pattern
        minutes: /1
      - platform: homeassistant
        event: start
    action:
      - service: weather.get_forecasts
        data:
          type: hourly
        target:
          entity_id: weather.domov
        response_variable: hourly
    weather:
      name: weather_domov_weather
      temperature_template: "{{ state_attr('weather.domov', 'temperature') }}"
      humidity_template: "{{ state_attr('weather.domov', 'humidity') }}"
      condition_template: "{{ state_attr('weather.domov', 'condition') }}"
      forecast_hourly_template: "{{ hourly['weather.domov'].forecast }}"

This example is a bit non-sense as it just tries to duplicate the weather entity. But I need to do more tricks there later. This is jsut a base.
The big BUT is that I cannot get the forecast in the newly created entity. The Weather Card shows only current state. In developer tools in States also no forecast is shown.
And if run the service get_forecasts I got an error I cannot explain myself

2024-04-05 14:45:21.915 INFO (MainThread) [homeassistant.helpers.script.websocket_api_script] websocket_api script: Running websocket_api script
2024-04-05 14:45:21.915 INFO (MainThread) [homeassistant.helpers.script.websocket_api_script] websocket_api script: Executing step call service
2024-04-05 14:45:21.915 ERROR (MainThread) [homeassistant.helpers.script.websocket_api_script] websocket_api script: Error executing script. Unexpected error for call_service at pos 1: dictionary update sequence element #0 has length 1; 2 is required
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 504, in _async_step
await getattr(self, handler)()
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 733, in _async_call_service_step
response_data = await self._async_run_long_action(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 696, in _async_run_long_action
return await long_task
^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/core.py", line 2542, in async_call
response_data = await coro
^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/core.py", line 2579, in _execute_service
return await target(service_call)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 971, in entity_service_call
single_response = await _handle_entity_call(
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 1043, in _handle_entity_call
result = await task
^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/components/weather/__init__.py", line 1075, in async_get_forecasts_service
converted_forecast_list = weather._convert_forecast(native_forecast_list)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/homeassistant/homeassistant/components/weather/__init__.py", line 722, in _convert_forecast
forecast_entry: dict[str, Any] = dict(_forecast_entry)
^^^^^^^^^^^^^^^^^^^^^
ValueError: dictionary update sequence element #0 has length 1; 2 is required

Any hints guys?

If I create sensor template instead of weather there is no issue to get forecast attribute filled by an array of forecast values. But that’s unusable for Weather Card of course.

I’m not arguing the benefits of this change, which there clearly are, but how convoluted its adoption is. Using the forecast attribute of a weather integration made this seamless. Now, it requires manually analysing the structure of the weather.get_forecasts response to know how to process it in the trigger-based sensors. The high friction of implementing this makes it certainly prone to mistakes and trial and error. Proof of this are the several threads with people tripping trying to get this working the new way.

By the way, what’s the reason for moving away from using attributes?

7 Likes

I am not a dev, but as I understand it, the main reason is to help keep the database as small as possible. The entity’s state object is saved to the database every time the state or an attribute updates. That means every time a weather entity’s state goes from “cloudy” to “partlycloudy” or the temperature attribute changes (which can happen multiple times an hour) the entire object, including the large forecast attribute, is saved again, even though the values of the forecast haven’t changed since they only update hourly or daily based on their source integration.

3 Likes

I still have issues with this new way of getting the forecasts. This is my code and it results in a complete empty sensor:

- trigger:
    - platform: time_pattern
      hours: "/1"
    - platform: homeassistant
      event: start
  action:
    - service: weather.get_forecasts
      data:
        type: daily
      target:
        entity_id: weather.home
      response_variable: daily
  sensor:
    - name: weathertomorrow
      state: "{{ daily['weather.home'].forecast[1].temperature }}"
      attributes: 
        date: "{{ as_timestamp(daily['weather.home'].forecast[1].datetime) | timestamp_custom('%-d') }}"
        lowtemp:  "{{ daily['weather.home'].forecast[1].templow }}"
        percipitation: "{{ daily['weather.home'].forecast[1].precipitation_probability }}"
        icon: "{{ daily['weather.home'].forecast[1].condition }}"
        day: "{{ as_timestamp(daily['weather.home'].forecast[1].datetime) | timestamp_custom('%A') | upper }}"
        month: "{{ as_timestamp(daily['weather.home'].forecast[1].datetime) | timestamp_custom('%B') }}"

I have tried the service call in developer tools and it gives this result:

weather.home:
  forecast:
    - datetime: "2024-04-07"
      condition: partlycloudy
      precipitation_probability: 0
      wind_bearing: 202
      is_daytime: true
      text: ""
      temperature: 19
      templow: 10
      wind_gust_speed: 50
      wind_speed: 20
      precipitation: 0
    - datetime: "2024-04-08"
      condition: lightning-rainy
      precipitation_probability: 100
      wind_bearing: 135
      is_daytime: true
      text: ""
      temperature: 19
      templow: 10
      wind_speed: 12
      precipitation: 6
    - datetime: "2024-04-09"
      condition: rainy
      precipitation_probability: 100
      wind_bearing: 225
      is_daytime: true
      text: ""
      temperature: 13
      templow: 13
      wind_gust_speed: 80
      wind_speed: 39
      precipitation: 1
    - datetime: "2024-04-10"
      condition: sunny
      precipitation_probability: 0
etc..

So what am I doing wrong?

It will contain data only after it’s triggered by either one of its two triggers. That means either by restarting Home Assistant or by waiting until the Time Pattern Trigger runs every hour (on the hour).

If you have restarted Home Assistant, or waited for more than an hour, and it still reports nothing, check the Log for errors.

You shouldn’t need to go into the attributes to get forecast information. They should be separate entities. The forecast attribute should only be for things like weather cards and voice responses.

Check your weather providers integration and look for forecast information as entities. Chances are, they exist now. I.e. still easy to access, just not in an attribute.

1 Like

I see. If the weather integration supports it already, I should be able to feed off its new interval forecast entity, which will have the data already formatted.

I’m using OpenWeatherMap, which doesn’t have this yet, but good to know the above.

So I created my new weather forecast attribute sensor which works (thanks to the community):

template:
  - trigger:
    - platform: state
      entity_id: weather.weather_met_no
    - platform: homeassistant
      event: start
    - platform: event
      event_type: event_template_reloaded
    action:
      - service: weather.get_forecasts
        data:
          type: hourly
        target:
          entity_id: weather.weather_met_no
        response_variable: hourly
    sensor:
      - name: Weather metno Hourly Forecast
        unique_id: weather_forecast_metno_hourly
        state: "{{ states('weather.weather_met_no') }}"
        attributes:
          forecast: "{{ hourly['weather.weather_met_no'].forecast }}"

However, when I try to combine this new sensor into my optimised weather entity, the forecast is no longer populated (it was popuplated previously to 2024.04). What am I doing wrong?

weather:  
  - platform: template
    name: "Weather optimised hourly"
    condition_template: "{{ states('sensor.weather_local_merged') }}"
    temperature_template: "{{ states('sensor.weather_local_temperature') | float}}"
    humidity_template: "{{ states('sensor.weather_local_humidity')| int }}"
    pressure_template: "{{ states('sensor.weather_local_sea_level_pressure')| float }}"
    wind_speed_template: "{{ ( states('sensor.weather_local_wind_speed_avg') | float * 18 / 5 ) | round(2) }}"
    wind_bearing_template: "{{ states('sensor.weather_local_wind_bearing_avg')| int }}"
    visibility_template: "{{ states('sensor.weather_local_visibility')| float }}"
    forecast_hourly_template: "{{ state_attr('sensor.weather_metno_hourly_forecast', 'forecast') }}"

When I put the hourly forecast
forecast_hourly_template: "{{ state_attr('sensor.weather_metno_hourly_forecast', 'forecast') }}" in the dev tools template editor, I get a big array the entiry hourly forecast as a result, so that alone works, but it no longer does return the attributes in the new weather sensor - is that on purpose, so the forecast attributes are also no longer displayed even for template weather entities??

1 Like

That should work and it’s the same way I finally got mine going. However, updating the sensor for first time was kind of weird, so I initially set a trigger of every 1 minute to ensure it did it soon enough. After verifying that the forecast was working again I then set the proper triggers.

Well, in fact I face the same problem as you and the “big array” you mentioned is probably not correct by my latest finding.
But still do no know how to move on.

My latest conclusion is that the integration is not ready for the new situation.
If I use Open Weather Map entity in my templates it works fine. If I use custom integration for Czech forecasts it does not work. And the “big array” looks different. The templates code is the same, only difference is source weather entity.

Ok, so having read all the replies and browsing the interweb a lot. I got myself a solution. A lot is repeat of earlier posts but I hope to add some gaps that made it hard for me to understand what I needed to do.

Situation: My goal is to have a sensor that shows the forecasted temperature of today. This to have logic on whether the shutters and skylight cover need to be closed for keeping the heat out. Or to have the sun help keep our heating bill low.

  1. So at first let’s be clear where we need to add these trigger template sensors. It has it’s own section so I added this line to my configurations.yaml
template: !include templates.yaml
  1. I created an actual templates.yaml in the home assistant home directory and added the following code:
- trigger:
    - platform: time_pattern
      hours: "/4"
    - platform: state
      entity_id: weather.huis
    - platform: homeassistant
      event: start
    - platform: event
      event_type: event_template_reloaded
  action:
    - service: weather.get_forecasts
      data:
        type: daily
      target:
        entity_id: weather.huis
      response_variable: daily
  sensor:
    - name: "Today's Temperature"
      state: "{{ daily['weather.huis'].forecast[0].temperature|float }}"
      attributes: 
        forecast: "{{ daily['weather.huis'].forecast }}"

Important here is to use the weather.huis that is actually your weather entity. Mine is from buienradar.

The entity at first shows the full array as an attribute so there you can look for the available data and its position and key name. If it’s empty check whether the weather entity has daily, hourly or twice-daily data. Change it throughout the codesnippet.

For me the trick is to have the actual number I required in the state declaration of the sensor. So change that Where you can you use the array position (in between the [#] )and the key ( .temperature in my case) to get the right information you need. In the code above it’s the;
“{{ daily[‘weather.huis’].forecast[0].temperature|float }}”
The float is only necessary if you want an actual number.

And yes I know I went overboard on the events where in the service gets triggered, but I wanted to be sure.

  1. First time you have the templates.yaml created you need to restart home assistant. Afterwards a reload of the template entities from the developer page is enough.

Hope this helps a lot of you out.

2 Likes

There is a issue on github related to this: Weather template validation is too strict and/or NWS integration returns bad forecasts · Issue #114799 · home-assistant/core · GitHub

Streamlining is great and I love the HA project. I think feature upgrades should make everyone’s life easier, however this one clearly went into the opposite, you now need a bachelor’s degree to sort out the weather forecast, if possible at all.
Mistakes can happen, no problem. But I think it would be better from the responsible people to own and address this problem.

Is it a problem? Well, from a user point of view, clearly yes. So many people are struggling at this stage, which means to me either its not communicated well, or not documented well. Honestly, I think for this one, both is the case plus the template weather is currently not working either.

I really hope this is getting addressed with one of the next releases. Thanks for all the work that is been done - this upgrade needs some tweaks though :slight_smile:

8 Likes