I wanted to create a nice looking weather forecast inside of Home Assistant that uses the mdi icons, so it looks like the rest of my home assistant sensors. Sure you can use a weather app, but this just seems nicer, and since I’m looking at my home assistant app so much anyways, it makes sense.
This uses the dark sky sensor component, but could be applied using other weather components. Dark sky assigns the suffix _2, _3, _4 for the forecast 2 days out, 3 days out, etc.
Below is an image of the end result and the code to create it.
EDIT 1/24/2018: I’ve revised the code to incorporate the improvements made by @mconway and @arsaboo .
EDIT 3/4/2018: See arsaboo’s post #173 for the updated code using the friendly name templating, which was introduced in version 0.64. If this works for you, you no longer need the python script that updates the friendly names for the forecast sensors. Some Hassio users are reporting that the friendly name templating is not working for them; if that’s the case for you, just use the python script method described in this post to update the friendly names.
Save the following as weather.yaml in a folder called packages, add packages: !include_dir_named packages
under homeassistant:
in the configuration.yaml file. See home assistant’s documentation on packages for more information.
sensor:
- platform: darksky
api_key: !secret darksky_api_key
forecast:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
monitored_conditions:
- summary
- temperature
- temperature_min
- temperature_max
- humidity
- precip_probability
- daily_summary
- icon
- platform: season
- platform: template
sensors:
weekday:
friendly_name: 'Weekday'
value_template: '{{ now().strftime("%A") }}'
forecast_today:
friendly_name: "Today's Forecast"
value_template: >
{{states.sensor.dark_sky_daily_high_temperature.state|round(0)}}°/{{states.sensor.dark_sky_daily_low_temperature.state|round(0)}}°/{{states.sensor.dark_sky_precip_probability.state|round(0)}}%
icon_template: >-
{% if is_state("sensor.dark_sky_icon", "clear-day") %}
mdi:weather-sunny
{% elif is_state("sensor.dark_sky_icon", "clear-night") %}
mdi:weather-night
{% elif is_state("sensor.dark_sky_icon", "cloudy") %}
mdi:weather-cloudy
{% elif is_state("sensor.dark_sky_icon", "rain") %}
mdi:weather-pouring
{% elif is_state("sensor.dark_sky_icon", "sleet") %}
mdi:weather-snowy-rain
{% elif is_state("sensor.dark_sky_icon", "snow") %}
mdi:weather-snowy
{% elif is_state("sensor.dark_sky_icon", "wind") %}
mdi:weather-windy
{% elif is_state("sensor.dark_sky_icon", "fog") %}
mdi:weather-fog
{% elif is_state("sensor.dark_sky_icon", "partly-cloudy-day") %}
mdi:weather-partlycloudy
{% elif is_state("sensor.dark_sky_icon", "partly-cloudy-night") %}
mdi:weather-partlycloudy
{% else %}
error
{% endif %}
forecast_1:
friendly_name: 'Tomorrow'
value_template: >
{{states.sensor.dark_sky_daily_high_temperature_1.state|round(0)}}°/{{states.sensor.dark_sky_daily_low_temperature_1.state|round(0)}}°/{{states.sensor.dark_sky_precip_probability_1.state|round(0)}}%
icon_template: >-
{% if is_state("sensor.dark_sky_icon_1", "clear-day") %}
mdi:weather-sunny
{% elif is_state("sensor.dark_sky_icon_1", "clear-night") %}
mdi:weather-night
{% elif is_state("sensor.dark_sky_icon_1", "cloudy") %}
mdi:weather-cloudy
{% elif is_state("sensor.dark_sky_icon_1", "rain") %}
mdi:weather-pouring
{% elif is_state("sensor.dark_sky_icon_1", "sleet") %}
mdi:weather-snowy-rain
{% elif is_state("sensor.dark_sky_icon_1", "snow") %}
mdi:weather-snowy
{% elif is_state("sensor.dark_sky_icon_1", "wind") %}
mdi:weather-windy
{% elif is_state("sensor.dark_sky_icon_1", "fog") %}
mdi:weather-fog
{% elif is_state("sensor.dark_sky_icon_1", "partly-cloudy-day") %}
mdi:weather-partlycloudy
{% elif is_state("sensor.dark_sky_icon_1", "partly-cloudy-night") %}
mdi:weather-partlycloudy
{% else %}
error
{% endif %}
forecast_2:
friendly_name: 'Second'
value_template: >
{{states.sensor.dark_sky_daily_high_temperature_2.state|round(0)}}°/{{states.sensor.dark_sky_daily_low_temperature_2.state|round(0)}}°/{{states.sensor.dark_sky_precip_probability_2.state|round(0)}}%
icon_template: >-
{% if is_state("sensor.dark_sky_icon_2", "clear-day") %}
mdi:weather-sunny
{% elif is_state("sensor.dark_sky_icon_2", "clear-night") %}
mdi:weather-night
{% elif is_state("sensor.dark_sky_icon_2", "cloudy") %}
mdi:weather-cloudy
{% elif is_state("sensor.dark_sky_icon_2", "rain") %}
mdi:weather-pouring
{% elif is_state("sensor.dark_sky_icon_2", "sleet") %}
mdi:weather-snowy-rain
{% elif is_state("sensor.dark_sky_icon_2", "snow") %}
mdi:weather-snowy
{% elif is_state("sensor.dark_sky_icon_2", "wind") %}
mdi:weather-windy
{% elif is_state("sensor.dark_sky_icon_2", "fog") %}
mdi:weather-fog
{% elif is_state("sensor.dark_sky_icon_2", "partly-cloudy-day") %}
mdi:weather-partlycloudy
{% elif is_state("sensor.dark_sky_icon_2", "partly-cloudy-night") %}
mdi:weather-partlycloudy
{% else %}
error
{% endif %}
forecast_3:
friendly_name: 'Third'
value_template: >
{{states.sensor.dark_sky_daily_high_temperature_3.state|round(0)}}°/{{states.sensor.dark_sky_daily_low_temperature_3.state|round(0)}}°/{{states.sensor.dark_sky_precip_probability_3.state|round(0)}}%
icon_template: >-
{% if is_state("sensor.dark_sky_icon_3", "clear-day") %}
mdi:weather-sunny
{% elif is_state("sensor.dark_sky_icon_3", "clear-night") %}
mdi:weather-night
{% elif is_state("sensor.dark_sky_icon_3", "cloudy") %}
mdi:weather-cloudy
{% elif is_state("sensor.dark_sky_icon_3", "rain") %}
mdi:weather-pouring
{% elif is_state("sensor.dark_sky_icon_3", "sleet") %}
mdi:weather-snowy-rain
{% elif is_state("sensor.dark_sky_icon_3", "snow") %}
mdi:weather-snowy
{% elif is_state("sensor.dark_sky_icon_3", "wind") %}
mdi:weather-windy
{% elif is_state("sensor.dark_sky_icon_3", "fog") %}
mdi:weather-fog
{% elif is_state("sensor.dark_sky_icon_3", "partly-cloudy-day") %}
mdi:weather-partlycloudy
{% elif is_state("sensor.dark_sky_icon_3", "partly-cloudy-night") %}
mdi:weather-partlycloudy
{% else %}
error
{% endif %}
forecast_4:
friendly_name: 'Fourth'
value_template: >
{{states.sensor.dark_sky_daily_high_temperature_4.state|round(0)}}°/{{states.sensor.dark_sky_daily_low_temperature_4.state|round(0)}}°/{{states.sensor.dark_sky_precip_probability_4.state|round(0)}}%
icon_template: >-
{% if is_state("sensor.dark_sky_icon_4", "clear-day") %}
mdi:weather-sunny
{% elif is_state("sensor.dark_sky_icon_4", "clear-night") %}
mdi:weather-night
{% elif is_state("sensor.dark_sky_icon_4", "cloudy") %}
mdi:weather-cloudy
{% elif is_state("sensor.dark_sky_icon_4", "rain") %}
mdi:weather-pouring
{% elif is_state("sensor.dark_sky_icon_4", "sleet") %}
mdi:weather-snowy-rain
{% elif is_state("sensor.dark_sky_icon_4", "snow") %}
mdi:weather-snowy
{% elif is_state("sensor.dark_sky_icon_4", "wind") %}
mdi:weather-windy
{% elif is_state("sensor.dark_sky_icon_4", "fog") %}
mdi:weather-fog
{% elif is_state("sensor.dark_sky_icon_4", "partly-cloudy-day") %}
mdi:weather-partlycloudy
{% elif is_state("sensor.dark_sky_icon_4", "partly-cloudy-night") %}
mdi:weather-partlycloudy
{% else %}
error
{% endif %}
forecast_5:
friendly_name: 'Fifth'
value_template: >
{{states.sensor.dark_sky_daily_high_temperature_5.state|round(0)}}°/{{states.sensor.dark_sky_daily_low_temperature_5.state|round(0)}}°/{{states.sensor.dark_sky_precip_probability_5.state|round(0)}}%
icon_template: >-
{% if is_state("sensor.dark_sky_icon_5", "clear-day") %}
mdi:weather-sunny
{% elif is_state("sensor.dark_sky_icon_5", "clear-night") %}
mdi:weather-night
{% elif is_state("sensor.dark_sky_icon_5", "cloudy") %}
mdi:weather-cloudy
{% elif is_state("sensor.dark_sky_icon_5", "rain") %}
mdi:weather-pouring
{% elif is_state("sensor.dark_sky_icon_5", "sleet") %}
mdi:weather-snowy-rain
{% elif is_state("sensor.dark_sky_icon_5", "snow") %}
mdi:weather-snowy
{% elif is_state("sensor.dark_sky_icon_5", "wind") %}
mdi:weather-windy
{% elif is_state("sensor.dark_sky_icon_5", "fog") %}
mdi:weather-fog
{% elif is_state("sensor.dark_sky_icon_5", "partly-cloudy-day") %}
mdi:weather-partlycloudy
{% elif is_state("sensor.dark_sky_icon_5", "partly-cloudy-night") %}
mdi:weather-partlycloudy
{% else %}
error
{% endif %}
forecast_6:
friendly_name: 'Sixth'
value_template: >
{{states.sensor.dark_sky_daily_high_temperature_6.state|round(0)}}°/{{states.sensor.dark_sky_daily_low_temperature_6.state|round(0)}}°/{{states.sensor.dark_sky_precip_probability_6.state|round(0)}}%
icon_template: >-
{% if is_state("sensor.dark_sky_icon_6", "clear-day") %}
mdi:weather-sunny
{% elif is_state("sensor.dark_sky_icon_6", "clear-night") %}
mdi:weather-night
{% elif is_state("sensor.dark_sky_icon_6", "cloudy") %}
mdi:weather-cloudy
{% elif is_state("sensor.dark_sky_icon_6", "rain") %}
mdi:weather-pouring
{% elif is_state("sensor.dark_sky_icon_6", "sleet") %}
mdi:weather-snowy-rain
{% elif is_state("sensor.dark_sky_icon_6", "snow") %}
mdi:weather-snowy
{% elif is_state("sensor.dark_sky_icon_6", "wind") %}
mdi:weather-windy
{% elif is_state("sensor.dark_sky_icon_6", "fog") %}
mdi:weather-fog
{% elif is_state("sensor.dark_sky_icon_6", "partly-cloudy-day") %}
mdi:weather-partlycloudy
{% elif is_state("sensor.dark_sky_icon_6", "partly-cloudy-night") %}
mdi:weather-partlycloudy
{% else %}
error
{% endif %}
forecast_7:
friendly_name: 'Seventh'
value_template: >
{{states.sensor.dark_sky_daily_high_temperature_7.state|round(0)}}°/{{states.sensor.dark_sky_daily_low_temperature_7.state|round(0)}}°/{{states.sensor.dark_sky_precip_probability_7.state|round(0)}}%
icon_template: >-
{% if is_state("sensor.dark_sky_icon_7", "clear-day") %}
mdi:weather-sunny
{% elif is_state("sensor.dark_sky_icon_7", "clear-night") %}
mdi:weather-night
{% elif is_state("sensor.dark_sky_icon_7", "cloudy") %}
mdi:weather-cloudy
{% elif is_state("sensor.dark_sky_icon_7", "rain") %}
mdi:weather-pouring
{% elif is_state("sensor.dark_sky_icon_7", "sleet") %}
mdi:weather-snowy-rain
{% elif is_state("sensor.dark_sky_icon_7", "snow") %}
mdi:weather-snowy
{% elif is_state("sensor.dark_sky_icon_7", "wind") %}
mdi:weather-windy
{% elif is_state("sensor.dark_sky_icon_7", "fog") %}
mdi:weather-fog
{% elif is_state("sensor.dark_sky_icon_7", "partly-cloudy-day") %}
mdi:weather-partlycloudy
{% elif is_state("sensor.dark_sky_icon_7", "partly-cloudy-night") %}
mdi:weather-partlycloudy
{% else %}
error
{% endif %}
group:
weather_card_today:
name: Today
view: no
entities:
- sensor.forecast_today
- sensor.dark_sky_temperature
- sensor.dark_sky_humidity
weather_card_forecast:
name: Forecast
view: no
entities:
- sensor.dark_sky_daily_summary
- sensor.forecast_1
- sensor.forecast_2
- sensor.forecast_3
- sensor.forecast_4
- sensor.forecast_5
- sensor.forecast_6
- sensor.forecast_7
automation:
- id: update_friendly_names
alias: "Update friendly names"
trigger:
- platform: state
entity_id:
- sensor.forecast_1
- sensor.forecast_2
- sensor.forecast_3
- sensor.forecast_4
- sensor.forecast_5
- sensor.forecast_6
- sensor.forecast_7
- platform: homeassistant
event: start
action:
- service: python_script.dark_sky_friendly_names
data_template:
entityid: '{{trigger.entity_id}}'
Python script to update the friendly names (save as dark_sky_friendly_names.py , place in /python_scripts folder and add python_script:
to your configuration.yaml file. See python scripts component for more information.) NOTE: I’ve modified lines 25, 33, 41, and 49 to use ‘icon’ instead of ‘entity_picture’ so that the mdi icons work. If you want to use custom icons, see links to @arsaboo 's code on github below.
###############################################################################
# Author: Alok R. Saboo
# Description: This script takes the dark_sky forecast sensors and updates
# their friendly_name to include the date and day.
# https://github.com/arsaboo/homeassistant-config/blob/master/packages/weather.yaml
###############################################################################
dark_sky_entities = ["sensor.forecast_1", "sensor.forecast_2", "sensor.forecast_3",
"sensor.forecast_4", "sensor.forecast_5", "sensor.forecast_6",
"sensor.forecast_7"]
days = ["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]
triggeredEntity = data.get('entity_id')
# logger.warning("trigger is {}".format(triggeredEntity))
now = datetime.datetime.now()
today = now.weekday()
if triggeredEntity is None:
for entity_id in dark_sky_entities:
# copy it's state
state = hass.states.get(entity_id)
newState = state.state
forecastdays = int(entity_id.split('_')[1])
day = datetime.timedelta(days = forecastdays)
forecastdate = now + day
newEntityPicture = state.attributes.get('icon')
if today + forecastdays > 6:
newDay = days[today + forecastdays - 7]
else:
newDay = days[today + forecastdays]
# Set states
hass.states.set(entity_id, newState, {
'friendly_name': "{} ({}/{})".format(newDay, forecastdate.month, forecastdate.day),
'icon': newEntityPicture,
})
else:
state = hass.states.get(triggeredEntity)
newState = state.state
forecastdays = int(triggeredEntity.split('_')[1])
day = datetime.timedelta(days = forecastdays)
forecastdate = now + day
newEntityPicture = state.attributes.get('icon')
if today + forecastdays > 6:
newDay = days[today + forecastdays - 7]
else:
newDay = days[today + forecastdays]
# Set states
hass.states.set(triggeredEntity, newState, {
'friendly_name': "{} ({}/{})".format(newDay, forecastdate.month, forecastdate.day),
'icon': newEntityPicture,
})
Links to latest files on github are below. Note that unedited, this code assumes the usage of custom icons, which you need to download per the instructions in the commented code. If you want to use mdi icons, just use the code above.
https://github.com/arsaboo/homeassistant-config/blob/master/packages/weather.yaml