New weather forecast template

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

How do I use separate forecast entities in a template weather provider? Specifically, how do I use e.g. the 10 separate daily high/low temperature forecast entities that AccuWeather provides me, and squeeze them into the forecast_daily_template of a custom weather provider?

That’s the correct structure. Template weather entities then expect:

forecast:
- condition: sunny
  ...

If I have gotten this correct the only way is by organizing the forecast data with the structure shown here. The template weather entity accepts a list of dictionaries with a predefined set of keys as shown on the linked table.

Existing weather integrations should respond to get_forecasts with the data already formatted as such.

My sensor responses in exaclty this way with all the keys, example of the state itself (incl. formatting):

forecast:
  - datetime: "2024-04-09"
    condition: rainy
    temperature: 21
    templow: 6
    precipitation: 8.7
  - datetime: "2024-04-10"
    condition: rainy
    temperature: 10
    templow: 5
    precipitation: 2.3

However, when putting the sensor into the template the format is weird, the array is no longer structured (if that makes sense):

forecast_daily_template: "{{ state_attr('sensor.weather_daily_forecast', 'forecast') }}"

the response is this:

forecast_daily_template: "[{'datetime': '2024-04-09', 'condition': 'rainy', 'temperature': 21.0, 'templow': 7.0, 'precipitation': 8.7}, {'datetime': '2024-04-10', 'condition': 'rainy', 'temperature': 10.0, 'templow': 5.0, 'precipitation': 2.3}, {'datetime': '2024-04-11', 'condition': 'partlycloudy', 'temperature': 18.0, 'templow': 5.0, 'precipitation': 0.0}, {'datetime': '2024-04-12', 'condition': 'partlycloudy', 'temperature': 21.0, 'templow': 7.0, 'precipitation': 0.0}, {'datetime': '2024-04-13', 'condition': 'sunny', 'temperature': 25.0, 'templow': 9.0, 'precipitation': 0.0}, {'datetime': '2024-04-14', 'condition': 'sunny', 'temperature': 24.0, 'templow': 13.0, 'precipitation': 0.0}]"


you mentioned you got the template weather sensor up and running, can you post an example from the devtools using this?: forecast_daily_template: "{{ state_attr('sensor.weather_daily_forecast', 'forecast') }}"

Thank you

Ok, that is the structure that I explained above in Python terminology - a list of dictionaries (each dictionary is enclosed by { }). Yaml represents that in a pretty-printed way. The only difference here is that the list itself is contained in a dictionary, under the forecast key.

Now you have to extract the list and feed it to the template weather.


I get the expected dictionary, as you:
forecast_daily_template: "{{ state_attr('sensor.openweathermap_hourly_forecast', 'forecast') }}"

forecast_daily_template: "[{'condition': 'clear-night', 'precipitation_probability': 0, 'datetime': '2024-04-09T06:00:00+00:00', 'wind_bearing': 123, 'cloud_coverage': 0, 'temperature': 45, 'pressure': 30.12, 'wind_speed': 6.64, 'precipitation': 0.0, 'humidity': 58},...]"


For thoroughness, this my complete hierarchy:

get_forecasts response from OpenWeatherMap
service: weather.get_forecasts
data:
  type: hourly
target:
  entity_id: weather.openweathermap

weather.openweathermap:
  forecast:
    - condition: cloudy
      precipitation_probability: 0
      datetime: "2024-04-09T06:00:00+00:00"
      wind_bearing: 123
      cloud_coverage: 100
      temperature: 45
      pressure: 30.12
      wind_speed: 6.64
      precipitation: 0
      humidity: 62
    - condition: cloudy
      ...
Poll the service and massage the response in the trigger-based template sensor
template:
  - trigger:
    - platform: time_pattern
      hours: /1
    action:
      - service: weather.get_forecasts
        data:
          type: hourly
        target:
          entity_id: weather.openweathermap
        response_variable: hourly_forecast
    sensor:
      - name: OpenWeatherMap Hourly Forecast
        unique_id: openweathermap_hourly_forecast
        state: "{{ now().isoformat() }}"
        attributes:
          forecast: "{{ hourly_forecast['weather.openweathermap'].forecast }}"
Feed the data to the template weather entity
weather:
  - platform: template
    unique_id: home_weather
    name: Home Weather
    condition_template: "{{ states('sensor.openweathermap_condition') }}"
    temperature_template: "{{ states('sensor.temperature_sensor_air_temperature') }}"
    temperature_unit: °F
    humidity_template: "{{ states('sensor.temperature_sensor_humidity') }}"
    wind_speed_template: "{{ states('sensor.openweathermap_wind_speed') }}"
    wind_speed_unit: mph
    wind_bearing_template: "{{ states('sensor.openweathermap_wind_bearing') }}"
    forecast_hourly_template: "{{ state_attr('sensor.openweathermap_hourly_forecast', 'forecast') }}"

Ok, ive been using ha for a couple of years. Mostly im a homekit person but delve into ha when i need to do something complex. Not an expert but i get by. Never used templates before and got to say the old method was far more easier to get my head around than this one. Bit im stuck on is where do you initiate the template, ie is it directly into the yaml config files. I cant see any gui or intergration wizard that can do it, and under the debug menu its only got a place to try the template out.

1 Like

yes, the template entities/sensors must be placed in the configuration.yaml and then reboot HA