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?
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 multipleweather entities.
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):
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.
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.
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 }}"
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:
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() }}"