renemarc/home-assistant-config

View on GitHub
sensors/atmosphere.yaml

Summary

Maintainability
Test Coverage
#
# 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 %}