sensors/atmosphere.yaml
#
# World Air Quality Index (WAQI)
#
# Ratings for templates below are USA ones instead of Canadians.
#
# Not all stations track the same air quality properties. Instead of hard-coding
# which station has what, the "aqi_*" template sensors check if a given
# attribute is available for each station in the "waqi" group. Dead stations and
# stale values are filtered out and an average attribute value is returned.
#
# @see /custom_components/waqi_custom/sensor.py
#
# @link https://en.wikipedia.org/wiki/Air_quality_index
# @link https://www.home-assistant.io/integrations/sensor.waqi/
#
- platform: waqi
token: !secret waqi_token
locations: !secret waqi_locations
stations: !secret waqi_stations
#
# WAQI: Active stations
#
# Since a template sensor will not be updated without parsable entities inside
# `value_template`, an `entity_id` key is used pointing to a regularly updated
# sensor.
#
- platform: template
sensors:
aqi_stations:
friendly_name: "AQI Stations"
icon_template: "mdi:radar"
entity_id:
- sensor.time_quarterly
value_template: >-
{% set attribute = 'name' %}
{% set max_hours_behind = 4 %}
{% set cutoff = (as_timestamp(now())|int - max_hours_behind * 60 * 60) | timestamp_local %}
{% set stations = states | selectattr('entity_id', 'in', state_attr('group.waqi', 'entity_id'))
| rejectattr('state', 'eq', 'unavailable')
| rejectattr('attributes.time', 'lt', cutoff)
| selectattr(attribute)
| map(attribute=attribute)
| join('|') %}
{% if stations %}
{{ stations }}
{% endif %}
aqi_stations_count:
friendly_name: "AQI Stations Count"
icon_template: "mdi:radar"
value_template: >-
{% set stations = states('sensor.aqi_stations') %}
{% if stations != '' %}
{{ stations.split('|') | length }}
{% else %}
0
{% endif %}
#
# WAQI: Average
#
# Since a template sensor will not be updated without parsable entities inside
# `value_template`, an `entity_id` key is used pointing to a regularly updated
# sensor.
#
- platform: template
sensors:
aqi:
friendly_name: "Air Quality Index"
icon_template: "mdi:chemical-weapon"
entity_id:
- sensor.time_quarterly
value_template: >-
{% set attribute = 'state' %}
{% set max_hours_behind = 4 %}
{% set cutoff = (as_timestamp(now())|int - max_hours_behind * 60 * 60) | timestamp_local %}
{% set stations = states | selectattr('entity_id', 'in', state_attr('group.waqi', 'entity_id'))
| rejectattr('state', 'eq', 'unavailable')
| rejectattr('attributes.time', 'lt', cutoff)
| selectattr(attribute)
| map(attribute=attribute)
| map('float')
| list %}
{% if stations %}
{{ (stations|sum / stations|length) | round }}
{% else %}
unknown
{% endif %}
aqi_friendly:
friendly_name: "Air Quality Index"
icon_template: "mdi:chemical-weapon"
value_template: >-
{% set index = states('sensor.aqi') | float(-1) %}
{% if index > 300 %}
Hazardous
{% elif index > 200 %}
Very Unhealthy
{% elif index > 150 %}
Unhealthy
{% elif index > 100 %}
Unhealthy for Sensitive Groups
{% elif index > 50 %}
Moderate
{% elif index >= 0 %}
Good
{% else %}
unknown
{% endif %}
#
# WAQI: Carbon monoxide
#
# Since a template sensor will not be updated without parsable entities inside
# `value_template`, an `entity_id` key is used pointing to a regularly updated
# sensor.
#
- platform: template
sensors:
aqi_carbon_monoxide:
friendly_name: "Carbon Monoxide"
icon_template: "mdi:fire"
unit_of_measurement: 'PPM'
entity_id:
- sensor.time_quarterly
value_template: >-
{% set attribute = 'attributes.co' %}
{% set max_hours_behind = 4 %}
{% set cutoff = (as_timestamp(now())|int - max_hours_behind * 60 * 60) | timestamp_local %}
{% set stations = states | selectattr('entity_id', 'in', state_attr('group.waqi', 'entity_id'))
| rejectattr('state', 'eq', 'unavailable')
| rejectattr('attributes.time', 'lt', cutoff)
| selectattr(attribute)
| map(attribute=attribute)
| map('float')
| list %}
{% if stations %}
{{ (stations|sum / stations|length) | round }}
{% else %}
unknown
{% endif %}
aqi_carbon_monoxide_friendly:
friendly_name: "Carbon Monoxide"
icon_template: "mdi:fire"
value_template: >-
{% set co = states('sensor.aqi_carbon_monoxide') | int(-1) %}
{% if co > 300 %}
Hazardous
{% elif co > 200 %}
Very Unhealthy
{% elif co > 150 %}
Unhealthy
{% elif co > 100 %}
Unhealthy for Sensitive Groups
{% elif co > 50 %}
Moderate
{% elif co >= 0 %}
Good
{% else %}
unknown
{% endif %}
#
# WAQI: Particulate matter 2.5μm
#
# Since a template sensor will not be updated without parsable entities inside
# `value_template`, an `entity_id` key is used pointing to a regularly updated
# sensor.
#
- platform: template
sensors:
aqi_particles:
friendly_name: "PM2.5"
icon_template: "mdi:chart-bubble"
unit_of_measurement: 'PPM'
entity_id:
- sensor.time_quarterly
value_template: >-
{% set attribute = 'attributes.pm_2_5' %}
{% set max_hours_behind = 4 %}
{% set cutoff = (as_timestamp(now())|int - max_hours_behind * 60 * 60) | timestamp_local %}
{% set stations = states | selectattr('entity_id', 'in', state_attr('group.waqi', 'entity_id'))
| rejectattr('state', 'eq', 'unavailable')
| rejectattr('attributes.time', 'lt', cutoff)
| selectattr(attribute)
| map(attribute=attribute)
| map('float')
| list %}
{% if stations %}
{{ (stations|sum / stations|length) | round }}
{% else %}
unknown
{% endif %}
aqi_particles_friendly:
friendly_name: "PM2.5"
icon_template: "mdi:chart-bubble"
value_template: >-
{% set pm25 = states('sensor.aqi_particles') | int(-1) %}
{% if pm25 > 300 %}
Hazardous
{% elif pm25 > 200 %}
Very Unhealthy
{% elif pm25 > 150 %}
Unhealthy
{% elif pm25 > 100 %}
Unhealthy for Sensitive Groups
{% elif pm25 > 50 %}
Moderate
{% elif pm25 >= 0 %}
Good
{% else %}
unknown
{% endif %}
#
# WAQI: Nitrogen dioxide
#
# Since a template sensor will not be updated without parsable entities inside
# `value_template`, an `entity_id` key is used pointing to a regularly updated
# sensor.
#
- platform: template
sensors:
aqi_nitrogen_dioxide:
friendly_name: "Nitrogen Dioxide"
icon_template: "mdi:car"
unit_of_measurement: 'PPM'
entity_id:
- sensor.time_quarterly
value_template: >-
{% set attribute = 'attributes.nitrogen_dioxide' %}
{% set max_hours_behind = 4 %}
{% set cutoff = (as_timestamp(now())|int - max_hours_behind * 60 * 60) | timestamp_local %}
{% set stations = states | selectattr('entity_id', 'in', state_attr('group.waqi', 'entity_id'))
| rejectattr('state', 'eq', 'unavailable')
| rejectattr('attributes.time', 'lt', cutoff)
| selectattr(attribute)
| map(attribute=attribute)
| map('float')
| list %}
{% if stations %}
{{ (stations|sum / stations|length) | round }}
{% else %}
unknown
{% endif %}
aqi_nitrogen_dioxide_friendly:
friendly_name: "Nitrogen Dioxide"
icon_template: "mdi:car"
value_template: >-
{% set nox = states('sensor.aqi_nitrogen_dioxide') | int(-1) %}
{% if nox > 300 %}
Off the Scale
{% elif nox > 200 %}
Very Unhealthy
{% elif nox > 150 %}
Unhealthy
{% elif nox > 100 %}
Unhealthy for Sensitive Groups
{% elif nox > 50 %}
Moderate
{% elif nox >= 0 %}
Good
{% else %}
unknown
{% endif %}
#
# WAQI: Ozone
#
# Since a template sensor will not be updated without parsable entities inside
# `value_template`, an `entity_id` key is used pointing to a regularly updated
# sensor.
#
- platform: template
sensors:
aqi_ozone:
friendly_name: "Ozone"
icon_template: "mdi:earth"
unit_of_measurement: 'PPM'
entity_id:
- sensor.time_quarterly
value_template: >-
{% set attribute = 'attributes.ozone' %}
{% set max_hours_behind = 4 %}
{% set cutoff = (as_timestamp(now())|int - max_hours_behind * 60 * 60) | timestamp_local %}
{% set stations = states | selectattr('entity_id', 'in', state_attr('group.waqi', 'entity_id'))
| rejectattr('state', 'eq', 'unavailable')
| rejectattr('attributes.time', 'lt', cutoff)
| selectattr(attribute)
| map(attribute=attribute)
| map('float')
| list %}
{% if stations %}
{{ (stations|sum / stations|length) | round }}
{% else %}
unknown
{% endif %}
aqi_ozone_friendly:
friendly_name: "Ozone"
icon_template: "mdi:earth"
value_template: >-
{% set ozone = states('sensor.aqi_ozone') | int(-1) %}
{% if ozone > 300 %}
Hazardous
{% elif ozone > 200 %}
Very Unhealthy
{% elif ozone > 150 %}
Unhealthy
{% elif ozone > 100 %}
Unhealthy for Sensitive Groups
{% elif ozone > 50 %}
Moderate
{% elif ozone >= 0 %}
Good
{% else %}
unknown
{% endif %}
#
# WAQI: Sulphur dioxide
#
# Since a template sensor will not be updated without parsable entities inside
# `value_template`, an `entity_id` key is used pointing to a regularly updated
# sensor.
#
- platform: template
sensors:
aqi_sulphur_dioxide:
friendly_name: "Sulphur Dioxide"
icon_template: "mdi:factory"
unit_of_measurement: 'PPM'
entity_id:
- sensor.time_quarterly
value_template: >-
{% set attribute = 'attributes.sulfur_dioxide' %}
{% set max_hours_behind = 4 %}
{% set cutoff = (as_timestamp(now())|int - max_hours_behind * 60 * 60) | timestamp_local %}
{% set stations = states | selectattr('entity_id', 'in', state_attr('group.waqi', 'entity_id'))
| rejectattr('state', 'eq', 'unavailable')
| rejectattr('attributes.time', 'lt', cutoff)
| selectattr(attribute)
| map(attribute=attribute)
| map('float')
| list %}
{% if stations %}
{{ (stations|sum / stations|length) | round }}
{% else %}
unknown
{% endif %}
aqi_sulphur_dioxide_friendly:
friendly_name: "Sulphur Dioxide"
icon_template: "mdi:factory"
value_template: >-
{% set so2 = states('sensor.aqi_sulphur_dioxide') | int(-1) %}
{% if so2 > 300 %}
Off the Scale
{% elif so2 > 200 %}
Very Unhealthy
{% elif so2 > 150 %}
Unhealthy
{% elif so2 > 100 %}
Unhealthy for Sensitive Groups
{% elif so2 > 50 %}
Moderate
{% elif so2 >= 0 %}
Good
{% else %}
unknown
{% endif %}
#
# Ultraviolet rays
#
# Makes the sensor agnostic from its Dark Sky data source in case of eventual
# replacement.
#
# @link https://en.wikipedia.org/wiki/Ultraviolet_index
#
- platform: template
sensors:
uv:
friendly_name: "UV Index"
icon_template: "mdi:sunglasses"
value_template: >-
{{ states('sensor.dark_sky_uv_index') }}
uv_0:
friendly_name: "UV Index"
icon_template: "mdi:sunglasses"
value_template: >-
{{ states('sensor.dark_sky_uv_index_0d') }}
uv_1:
friendly_name: "UV Index"
icon_template: "mdi:sunglasses"
value_template: >-
{{ states('sensor.dark_sky_uv_index_1d') }}
uv_2:
friendly_name: "UV Index"
icon_template: "mdi:sunglasses"
value_template: >-
{{ states('sensor.dark_sky_uv_index_2d') }}
uv_3:
friendly_name: "UV Index"
icon_template: "mdi:sunglasses"
value_template: >-
{{ states('sensor.dark_sky_uv_index_3d') }}
uv_4:
friendly_name: "UV Index"
icon_template: "mdi:sunglasses"
value_template: >-
{{ states('sensor.dark_sky_uv_index_4d') }}
uv_friendly:
friendly_name: "UV Index"
icon_template: "mdi:sunglasses"
value_template: >-
{% set uv = states('sensor.uv') | int(-1) %}
{% if uv >= 11 %}
Extreme
{% elif uv >= 8 %}
Very high
{% elif uv >= 6 %}
High
{% elif uv >= 3 %}
Moderate
{% elif uv >= 0 %}
Low
{% else %}
unknown
{% endif %}
uv_friendly_0:
friendly_name: "UV Index"
icon_template: "mdi:sunglasses"
value_template: >-
{% set uv = states('sensor.uv_0') | int(-1) %}
{% if uv >= 11 %}
Extreme
{% elif uv >= 8 %}
Very high
{% elif uv >= 6 %}
High
{% elif uv >= 3 %}
Moderate
{% elif uv >= 0 %}
Low
{% else %}
unknown
{% endif %}
uv_friendly_1:
friendly_name: "UV Index"
icon_template: "mdi:sunglasses"
value_template: >-
{% set uv = states('sensor.uv_1') | int(-1) %}
{% if uv >= 11 %}
Extreme
{% elif uv >= 8 %}
Very high
{% elif uv >= 6 %}
High
{% elif uv >= 3 %}
Moderate
{% elif uv >= 0 %}
Low
{% else %}
unknown
{% endif %}
uv_friendly_2:
friendly_name: "UV Index"
icon_template: "mdi:sunglasses"
value_template: >-
{% set uv = states('sensor.uv_2') | int(-1) %}
{% if uv >= 11 %}
Extreme
{% elif uv >= 8 %}
Very high
{% elif uv >= 6 %}
High
{% elif uv >= 3 %}
Moderate
{% elif uv >= 0 %}
Low
{% else %}
unknown
{% endif %}
uv_friendly_3:
friendly_name: "UV Index"
icon_template: "mdi:sunglasses"
value_template: >-
{% set uv = states('sensor.uv_3') | int(-1) %}
{% if uv >= 11 %}
Extreme
{% elif uv >= 8 %}
Very high
{% elif uv >= 6 %}
High
{% elif uv >= 3 %}
Moderate
{% elif uv >= 0 %}
Low
{% else %}
unknown
{% endif %}
uv_friendly_4:
friendly_name: "UV Index"
icon_template: "mdi:sunglasses"
value_template: >-
{% set uv = states('sensor.uv_4') | int(-1) %}
{% if uv >= 11 %}
Extreme
{% elif uv >= 8 %}
Very high
{% elif uv >= 6 %}
High
{% elif uv >= 3 %}
Moderate
{% elif uv >= 0 %}
Low
{% else %}
unknown
{% endif %}