I recently got a PurpleAir indoor air quality sensor. It took me a bit to figure out how to integrate the JSON responses from their API into Home Assistant, so I thought I’d share my config here for folks to copy and improve.
From my configuration.yaml
:
sensor:
- platform: rest
name: 'PurpleAir'
# Substitute in the URL of the sensor you care about. To find the URL, go
# to purpleair.com/map, find your sensor, click on it, click on "Get This
# Widget" then click on "JSON".
resource: https://www.purpleair.com/json?show=40509&key=HWSALTZNT199YJWT
# Only query once a minute to avoid rate limits:
scan_interval: 60
# Set this sensor to be the AQI value.
#
# Code translated from JavaScript found at:
# https://docs.google.com/document/d/15ijz94dXJ-YAZLi9iZ_RaBwrZ4KtYeCy08goGBwnbCU/edit#
value_template: >
{% macro calcAQI(Cp, Ih, Il, BPh, BPl) -%}
{{ (((Ih - Il)/(BPh - BPl)) * (Cp - BPl) + Il)|round }}
{%- endmacro %}
{% if (value_json["results"][0]["PM2_5Value"]|float) > 1000 %}
invalid
{% elif (value_json["results"][0]["PM2_5Value"]|float) > 350.5 %}
{{ calcAQI((value_json["results"][0]["PM2_5Value"]|float), 500.0, 401.0, 500.0, 350.5) }}
{% elif (value_json["results"][0]["PM2_5Value"]|float) > 250.5 %}
{{ calcAQI((value_json["results"][0]["PM2_5Value"]|float), 400.0, 301.0, 350.4, 250.5) }}
{% elif (value_json["results"][0]["PM2_5Value"]|float) > 150.5 %}
{{ calcAQI((value_json["results"][0]["PM2_5Value"]|float), 300.0, 201.0, 250.4, 150.5) }}
{% elif (value_json["results"][0]["PM2_5Value"]|float) > 55.5 %}
{{ calcAQI((value_json["results"][0]["PM2_5Value"]|float), 200.0, 151.0, 150.4, 55.5) }}
{% elif (value_json["results"][0]["PM2_5Value"]|float) > 35.5 %}
{{ calcAQI((value_json["results"][0]["PM2_5Value"]|float), 150.0, 101.0, 55.4, 35.5) }}
{% elif (value_json["results"][0]["PM2_5Value"]|float) > 12.1 %}
{{ calcAQI((value_json["results"][0]["PM2_5Value"]|float), 100.0, 51.0, 35.4, 12.1) }}
{% elif (value_json["results"][0]["PM2_5Value"]|float) >= 0.0 %}
{{ calcAQI((value_json["results"][0]["PM2_5Value"]|float), 50.0, 0.0, 12.0, 0.0) }}
{% else %}
invalid
{% endif %}
unit_of_measurement: "AQI"
# The value of the sensor can't be longer than 255 characters, but the
# attributes can. Store away all the data for use by the templates below.
json_attributes:
- results
- platform: template
sensors:
purpleair_description:
friendly_name: 'PurpleAir AQI Description'
value_template: >
{% if (states('sensor.purpleair')|float) >= 401.0 %}
Hazardous
{% elif (states('sensor.purpleair')|float) >= 301.0 %}
Hazardous
{% elif (states('sensor.purpleair')|float) >= 201.0 %}
Very Unhealthy
{% elif (states('sensor.purpleair')|float) >= 151.0 %}
Unhealthy
{% elif (states('sensor.purpleair')|float) >= 101.0 %}
Unhealthy for Sensitive Groups
{% elif (states('sensor.purpleair')|float) >= 51.0 %}
Moderate
{% elif (states('sensor.purpleair')|float) >= 0.0 %}
Good
{% else %}
undefined
{% endif %}
entity_id: sensor.purpleair
purpleair_pm25:
friendly_name: 'PurpleAir PM 2.5'
value_template: "{{ state_attr('sensor.purpleair','results')[0]['PM2_5Value'] }}"
unit_of_measurement: "μg/m3"
entity_id: sensor.purpleair
purpleair_temp:
friendly_name: 'PurpleAir Temperature'
value_template: "{{ state_attr('sensor.purpleair','results')[0]['temp_f'] }}"
unit_of_measurement: "°F"
entity_id: sensor.purpleair
purpleair_humidity:
friendly_name: 'PurpleAir Humidity'
value_template: "{{ state_attr('sensor.purpleair','results')[0]['humidity'] }}"
unit_of_measurement: "%"
entity_id: sensor.purpleair
purpleair_pressure:
friendly_name: 'PurpleAir Pressure'
value_template: "{{ state_attr('sensor.purpleair','results')[0]['pressure'] }}"
unit_of_measurement: "mb"
entity_id: sensor.purpleair