PurpleAir Air Quality Sensor

This is the information I wanted; thank you.
I was planing to do something similar for my exhaust fans whether or not to run based on a comparison of indoor and outdoor air quality.
I currently have one of my three exhaust fans set to an automation (in HA) based on humidity.
I still have my ‘main’ exhaust fan set on a every 6 hour schedule, this is the one I will hamper based on air quality. I am waiting for my own PurpleAir before I implement since the outdoor one I am using is several miles away.

Notifications for Air Quality sent to mine and my wife’s phones.
All of this being based on the custom sensor from above.

- id: '1602015312411'
  alias: Air Quality Notification 1 Good
  description: ''
  trigger:
  - platform: state
    entity_id: sensor.purpleair_description
    to: Good
    for: 0:10:00
  condition:
  - condition: time
    before: '20:00:00'
    after: 07:00:00
  action:
  - service: notify.mobile_app_gphone
    data:
      message: Air Quaility is Good
  - service: notify.mobile_app_sm_g950u
    data:
      message: Air Quaility is Good
  mode: single

- id: '1602009421488'
  alias: Air Quality Notification 2 Moderate
  description: ''
  trigger:
  - platform: state
    entity_id: sensor.purpleair_description
    to: Moderate
    for: 0:10:00
  condition:
  - condition: time
    before: '20:00:00'
    after: 07:00:00
  action:
  - service: notify.mobile_app_gphone
    data:
      message: Air Quaility is Moderate
  - service: notify.mobile_app_sm_g950u
    data:
      message: Air Quaility is Moderate
  mode: single

- id: '1602017331248'
  alias: Air Quality Notification 3 Unhealthy for Sensitive Groups
  description: ''
  trigger:
  - platform: state
    entity_id: sensor.purpleair_description
    for: 0:10:00
    to: Unhealthy for Sensitive Groups
  condition:
  - condition: time
    before: '20:00:00'
    after: 07:00:00
  action:
  - service: notify.mobile_app_gphone
    data:
      message: Air Quaility is Unhealthy for Sensitive Groups
  - service: notify.mobile_app_sm_g950u
    data:
      message: Air Quaility is Unhealthy for Sensitive Groups
  mode: single

- id: '1602017478518'
  alias: Air Quality Notification 4 Unhealthy
  description: ''
  trigger:
  - platform: state
    entity_id: sensor.purpleair_description
    to: Unhealthy
    for: 0:10:00
  condition:
  - condition: time
    before: '20:00:00'
    after: 07:00:00
  action:
  - service: notify.mobile_app_gphone
    data:
      message: Air Quaility is Unhealthy
  - service: notify.mobile_app_sm_g950u
    data:
      message: Air Quaility is Unhealthy
  mode: single

- id: '1602017682704'
  alias: Air Quality Notification 5 Very Unhealthy
  description: ''
  trigger:
  - platform: state
    entity_id: sensor.purpleair_description
    to: Very Unhealthy
    for: 0:10:00
  condition:
  - condition: time
    before: '20:00:00'
    after: 07:00:00
  action:
  - service: notify.mobile_app_gphone
    data:
      message: Air Quaility is Very Unhealthy
  - service: notify.mobile_app_sm_g950u
    data:
      message: Air Quaility is Very Unhealthy
  mode: single

- id: '1602017729305'
  alias: Air Quality Notification 6 Hazardous
  description: ''
  trigger:
  - platform: state
    entity_id: sensor.purpleair_description
    to: Hazardous
    for: 0:10:00
  condition:
  - condition: time
    before: '20:00:00'
    after: 07:00:00
  action:
  - service: notify.mobile_app_gphone
    data:
      message: Air Quaility is Hazardous
  - service: notify.mobile_app_sm_g950u
    data:
      message: Air Quaility is Hazardous
  mode: single

- id: '1602035435658'
  alias: Air Quality Notification 7 Very Hazardous
  description: ''
  trigger:
  - platform: state
    entity_id: sensor.purpleair_description
    to: Very Hazardous
    for: 0:10:00
  condition:
  - condition: time
    before: '20:00:00'
    after: 07:00:00
  action:
  - service: notify.mobile_app_gphone
    data:
      message: Air Quaility is Very Hazardous
  - service: notify.mobile_app_sm_g950u
    data:
      message: Air Quaility is Very Hazardous
  mode: single

Try to reload the integrations page - I had the same problem, then purple showed up in the list after restart and browser reload.

1 Like

The internal JSON API appears to return the 120sec by default (?live=false). If you want real time, just add ?live=true

I noticed PurpleAir added a US EPA conversion to their list of available conversions. I find it better tracks the EPA ratings with wildfire smoke. Specifically LRAPA seems to reasonably match AirNow official sensors for lower smoke levels, but for extreme smoke levels (AirNow AQI 180+), LRAPA seems to come in much too low.

I might play around with switching to the PurpleAir US EPA conversion formula, or maybe update the component to provide multiple conversions at once.

Here’s the listed conversions with the formulas they use as of today 2020-10-10:

US EPA: Courtesy of the United States Environmental Protection Agency Office of Research and Development, correction equation from their US wide study validated for wildfire and woodsmoke. 0-250 ug/m3 range (>250 may underestimate true PM2.5):PM2.5 (µg/m³) = 0.534 x PA(cf_1) - 0.0844 x RH + 5.604

AQandU: Courtesy of the University of Utah, conversion factors from their study of the PA sensors during winter in Salt Lake City. Visit their web site. PM2.5 (µg/m³) = 0.778 x PA + 2.65

LRAPA: Courtesy of the Lane Regional Air Protection Agency, conversion factors from their study of the PA sensors. Visit their web site. 0 - 65 µg/m³ range:LRAPA PM2.5 (µg/m³) = 0.5 x PA (PM2.5 CF=ATM) – 0.66

Simplified … a little (all in one automation vice several),
I could not come up with a simple way to simply the state change without getting it for every value change in AQI.

- id: '1602015312411'
  alias: Air Quality Notification Change
  description: ''
  trigger:
  - platform: state
    entity_id: sensor.purpleair_description
    to: Good
    for: 0:10:00
  - platform: state
    entity_id: sensor.purpleair_description
    to: Moderate
    for: 0:10:00
  - platform: state
    entity_id: sensor.purpleair_description
    to: Unhealthy for Sensitive Groups
    for: 0:10:00
  - platform: state
    entity_id: sensor.purpleair_description
    for: 0:10:00
    to: Unhealthy
  - platform: state
    entity_id: sensor.purpleair_description
    for: 0:10:00
    to: Very Unhealthy
  - platform: state
    entity_id: sensor.purpleair_description
    for: 0:10:00
    to: Hazardous
  - platform: state
    entity_id: sensor.purpleair_description
    to: Very Hazardous
    for: 0:10:00
  condition:
  - condition: time
    before: '20:00:00'
    after: 07:00:00
  action:
  - service: notify.mobile_app_gphone
    data:
      message: Air Quaility is {{ states('sensor.purpleair_description') }} at AQI
        {{ states('sensor.purpleair_aqi') }}
  mode: single

Temp sensor is off by 8 degrees! Easy fix:


value_template: "{{ state_attr('sensor.purpleair','results')[0]['temp_f'] | int - 8}}"

I just recieved teh PurpleAir PA-I-Indoor sensor and set it up. The local api works great, it’s just a rest call to http://x.x.x.x/json?live=true

This is even more simplified for an automation. I mis-read the description for leaving state blank, and have verified that this works without extra notifications.
This will send a notification between the hours of 0700-2100 for any change in air quality (i.e. from Good to Moderate; the change must be for at least 10 minutes to prevent spurious notifications). I have a separate automation to send a notification at 0700 reporting the air quality at that time.

- id: '1602977146994'
  alias: Air Quality Notification Change (Simple)
  description: ''
  trigger:
  - platform: state
    entity_id: sensor.purpleair_description
    for: 0:10:00
  condition:
  - condition: time
    before: '21:00:00'
    after: 07:00:00
  action:
  - service: notify.mobile_app_gphone
    data:
      message: Air Quaility is {{ states('sensor.purpleair_description') }} at AQI
        {{ states('sensor.purpleair_aqi') }}
    mode: single

Thanks, now I am more confident in getting both an indoor and an outdoor sensor.

As much as possible I try to get things that have local control; it does not bother me if it has cloud access but I don’t like the things that require it. I would have gotten this anyway but I feel better knowing it is accessible locally.

@ozczecho could you give a little more detail.
I have tried the canvas gauge in the past and just tried again but have not been successful with it, that is why I went with an imported grafana graph.

I installed via HACS and tried to put in as both a manual card and a picture entry; but with no luck. I can only get a “No card type configured.” I am sure it is something simple, but it eludes me at this time.

I tried your example and also the examples from the github page, same result.
I tried on at least HA 115 and 116.

Hi @GlennHA,

I am currently on HA 0.115. I don’t use HACS - so I cannot help there.

I copied the source file canvas-gauge-card.js into /www/custom-lovelace

In my configuration.yaml, I have:

lovelace:
  mode: yaml
  resources:
     
    - url: /local/custom-lovelace/canvas-gauge-card.js?v=1.2
      type: module

And then

  - type: vertical-stack
    title: A stack of cards
    cards:
    - type: custom:canvas-gauge-card
      card_height: 200
      entity: sensor.purpleair
      name: AQI reading
      gauge:
        type: "radial-gauge"
        title: AQI
        width: 200
        height: 200
        minValue: 0
        maxValue: 500
        startAngle: 40
        ticksAngle: 280
        valueBox: true
        majorTicks: ["0", "50", "100", "150", "200", "250", "300", "350", "400", "450", "500"]
        minorTicks: 10
        strokeTicks: true
        highlights: [{"from": 0, "to": 50,"color": "rgba(104, 225, 67, .75)"},{"from": 50, "to": 100,"color": "rgba(255, 255, 85, .75)"},{"from": 100, "to": 150,"color": "rgba(239, 133, 51, .75)"},{"from": 150, "to": 200,"color": "rgba(234, 51, 36, .75)"},{"from": 200, "to": 300,"color": "rgba(140, 26, 75, .75)"},{"from": 300, "to": 500,"color": "rgba(115, 20, 37, .75)"}]
        borders: no
        needleType: "arrow"
        needleWidth: 4
        needleCircleSize: 7
        needleCircleOuter: true
        needleCircleInner: false
        animationDuration: 1500
        animationRule: "linear"
        valueBoxBorderRadius: 10
        colorValueBoxRect: "#222"
        colorValueBoxRectEnd: "#333"
        valueDec: 2
        valueInt: 2

I hope that helps .

I am finding your discussion on Purple AQI interesting and helpful, thanks. I am experimenting with ways to present Purple AQI data. I have found the custom lovelace mini-graph-card to offer some interesting options for visualizing this data. Code and examples below:

# 24 hour average

        - type: custom:mini-graph-card
          entities:
            - sensor.purple_aqi_sb_average_current
          unit: " "
          name: "Santa Barbara AQI from Purple (24h)"
          icon: mdi:smog
          show:
            fill: false
            legend: false
            labels: false
            name: true
            points: true
            name_adaptive_color: true
            icon_adaptive_color: true
            show_legend: false
          font_size: 75
          line_width: 3
          points_per_hour: 4
          hours_to_show: 24
          color_thresholds:
            - value: 0
              color: '#00e500' # green
            - value: 50.42
              color: '#fffe0a' # yellow
            - value: 147.92
              color: '#fe7f03' # orange
            - value: 231.25
              color: '#ff0200' # red
            - value: 627.1
              color: '#98004c' # purple
            - value: 1043.75
              color: '#7f0024' # dark purple
            - value: 1460.42
              color: '#7f0024' # dark purple

# 7 day min max graph

        - type: custom:mini-graph-card
          entities:
            - entity: sensor.purple_aqi_sb_average_current
              aggregate_func: max
              name: Max
              color: #e74c3c
            - entity: sensor.purple_aqi_sb_average_current
              aggregate_func: min
              name: Min
            - entity: sensor.purple_aqi_sb_average_current
              aggregate_func: avg
              name: Avg
              color: green
          name: Santa Barbara AQI from Purple (7d)
          icon: mdi:smog
          hours_to_show: 168
          group_by: date
1 Like

Thank you, I finally got it…
I had an indention issue, one little mistake causes many hours of beating your head into the wall

Blockquote

This post should be a sticky somewhere on this site.

I like the mini-graph and started using it with canvas-graph.
I was able to pull multiple items on one graph, but I was not able to figure out how to do the vertical-stack with the mini-graph. I can do horizontal and vertical with canvas-graph.

I think you are referring to ‘canvas-gauge’. From a useful data visualization standpoint I have equated those to pie charts… like a box of chocolates to be used in great moderation :wink: I would think a vertical thermometer gauge might be more representative, with higher being worse. As for your point on how to combine vertical and horizontal lovelace entities, you might want to query the author of ‘mini-graph’, perhaps on github with both your questions and ideas for enhancements.

From a soap box standpoint, I think there are great opportunities for improving graphing and other presentation formats in lovelace to make it easier to absorb your current environments ‘state’. I am excited to see people creating enhancement to lovelace using javascript. I think HA is a place where these useful presentations of home status will massively improve (for all home automations tools), similar to what D3 did for data visualization in general.

Good hunting and good health AQI (whatever scale it is :wink: )

Yep,
Listen to what I mean, not what I say.

I liked your graph and tweaked it for my liking.
I’m debating between these two:


I think I like the sudden color change vice the gradual since it will display orange if it is on the high end of the green band or low of the yellow; and since the ‘orange’ band is actually above the yellow…it makes it slightly confusing.

Sudden Change

type: vertical-stack
cards:
  - type: horizontal-stack
    cards:
      - entities:
          - entity: sensor.purpleair_description
            name: Air Quality is
            icon: blank
        show_header_toggle: false
        type: entities
  - type: 'custom:mini-graph-card'
    entities:
      - sensor.purpleair_aqi
    unit: AQI
    name: AQI from Purple (24h)
    icon: 'mdi:chemical-weapon'
    show:
      fill: true
      legend: false
      labels: false
      name: true
      points: false
      name_adaptive_color: true
      icon_adaptive_color: true
      show_legend: false
    font_size: 75
    line_width: 3
    points_per_hour: 4
    hours_to_show: 24
    color_thresholds:
      - value: 0
        color: '#00e500'
      - value: 50
        color: '#00e500'
      - value: 50.5
        color: '#fffe0a'
      - value: 100
        color: '#fffe0a'
      - value: 100.5
        color: '#fe7f03'
      - value: 150
        color: '#fe7f03'
      - value: 150.5
        color: '#ff0200'
      - value: 200
        color: '#ff0200'
      - value: 200.5
        color: '#98004c'
      - value: 300.5
        color: '#7f0024'

Gradual Change

type: vertical-stack
cards:
  - type: horizontal-stack
    cards:
      - entities:
          - entity: sensor.purpleair_description
            name: Air Quality is
            icon: blank
        show_header_toggle: false
        type: entities
  - type: 'custom:mini-graph-card'
    entities:
      - sensor.purpleair_aqi
    unit: AQI
    name: AQI from Purple (24h)
    icon: 'mdi:chemical-weapon'
    show:
      fill: true
      legend: false
      labels: false
      name: true
      points: false
      name_adaptive_color: true
      icon_adaptive_color: true
      show_legend: false
    font_size: 75
    line_width: 3
    points_per_hour: 4
    hours_to_show: 24
    color_thresholds:
      - value: 0
        color: '#00e500'
      - value: 50.5
        color: '#fffe0a'
      - value: 100.5
        color: '#fe7f03'
      - value: 150.5
        color: '#ff0200'
      - value: 200.5
        color: '#98004c'
      - value: 300.5
        color: '#7f0024'

I am still looking for a good alternative to what I have for the Air Quality Description. If anyone knows a card that I can change color for the text based on value, I would be thankful. I did not see a way to change the ‘title’ dynamically or via a variable.

3 Likes

I’ve been exploring this lovelace custom element for a different use, but is very powerful. I believe I saw some folks using this and another custom element for color change of lovelace element. If the color of an element is specified as an attribute, using this custom element you should be able to change it based on any HA sensor attribute. Working with this custom element is complex, don’t get frustrated.

Here is an example I am doing to dynamically modify the standard glance card to change three attributes of each element based on sensor attributes:

  1. change card name
  2. change card icon
  3. change card tap action
     - type: 'custom:config-template-card'
        variables:
          - states['sensor.pulsepoint_pasa'].state
        entities:
          - sensor.pulsepoint_pasa
        card:
          type: glance
          title: "Pasadena Fire Department"
          entities:
            - entity: sensor.pulsepoint_pasa
              name: "${ states['sensor.pulsepoint_pasa'].attributes.time_local + ' ' + states['sensor.pulsepoint_pasa'].attributes.address }"
              icon: "${states['sensor.pulsepoint_pasa'].attributes.close_to_key_location ? 'mdi:home-alert-outline' : 'mdi:eye-outline'}"
              tap_action:
                action: url
                url_path: "${ 'https://maps.google.com/maps?&z=10&mrt=yp&t=k&layer=t&q=' + states['sensor.pulsepoint_pasa'].attributes.latitude + '+' + states['sensor.pulsepoint_pasa'].attributes.longitude }"