Dewpoint Comfort Level Display

Background: I just recently received my own PurpleAir for air quality measurements. The PurpleAir topic here has some excellent information to get started, even if you don’t have your own; I used a sensor that was a few miles from my house initially until I received mine. My graphs for the year are relatively blank since I established new sensors and hence starting from only the last week.

Anyway, here are my setups for Air Quality and Comfort Level.
I am looking for input on any tweaking that might be beneficial.
I will probably be creating graphs for outside temperature and humidity with some type of ‘zoning’ for comfort.
I currently utilizing the AQI for notifications to phones and TTS to a speaker whenever the quality changes (i.e. Good to Moderate) via automation.
I intentionally kept the colors similar from AQI to Dewpoint.

Config info:

- platform: template
  sensors:
    purpleair_dewpoint_description:
      friendly_name: 'PurpleAir DewPoint Description'
      value_template: >
        {% if (states('sensor.purpleair_dewpoint')|float) >= 75.5 %}
          Miserable
        {% elif (states('sensor.purpleair_dewpoint')|float) >= 70.5 %}
          Oppressive
        {% elif (states('sensor.purpleair_dewpoint')|float) >= 65.5 %}
          Uncomfortable
        {% elif (states('sensor.purpleair_dewpoint')|float) >= 60.5 %}
          Getting Sticky
        {% elif (states('sensor.purpleair_dewpoint')|float) >= 55.5 %}
          Comfortable
        {% elif (states('sensor.purpleair_dewpoint')|float) >= 0.0 %}
          Pleasant
        {% else %}
          undefined
        {% endif %}
      entity_id: sensor.purpleair

UI for Dewpoint:

type: vertical-stack
cards:
  - type: 'custom:button-text-card'
    title: |
      [[[ return states["sensor.purpleair_dewpoint_description"].state ]]]
    subtitle: Comfort Level
    icon_size: 55
    icon_color: |
      [[[
        if(states["sensor.purpleair_dewpoint"].state > 65){
          return 'white';
        } else if(states["sensor.purpleair_dewpoint"].state > 30){
          return 'black';
        } else{
          return 'white';
        }
      ]]]
    icon: |
      [[[
        if(states["sensor.purpleair_dewpoint"].state > 80){
          return 'mdi:emoticon-dead';
        } else if(states["sensor.purpleair_dewpoint"].state > 75){
          return 'mdi:emoticon-cry';
        } else if(states["sensor.purpleair_dewpoint"].state > 70){
          return 'mdi:emoticon-sad';
        } else if(states["sensor.purpleair_dewpoint"].state > 65){
          return 'mdi:emoticon-confused';
        } else if(states["sensor.purpleair_dewpoint"].state > 60){
          return 'mdi:emoticon-neutral';
        } else if(states["sensor.purpleair_dewpoint"].state > 55){
          return 'mdi:emoticon-happy';
        } else if(states["sensor.purpleair_dewpoint"].state > 50){
          return 'mdi:emoticon-excited';
        } else if(states["sensor.purpleair_dewpoint"].state > 30){
          return 'mdi:emoticon-happy';
        } else if(states["sensor.purpleair_dewpoint"].state > 0){
          return 'mdi:emoticon-neutral';
        } else{
          return 'mdi:emoticon-confused';
        }
      ]]]
    font_color: |
      [[[
        if(states["sensor.purpleair_dewpoint"].state > 65){
          return 'white';
        } else if(states["sensor.purpleair_dewpoint"].state > 30){
          return 'black';
        } else{
          return 'white';
        }
      ]]]
    large: true
    background_color: |
      [[[
        if(states["sensor.purpleair_dewpoint"].state > 80){
          return '#731425';
        } else if(states["sensor.purpleair_dewpoint"].state > 75){
          return '#8c1a4b';
        } else if(states["sensor.purpleair_dewpoint"].state > 70){
          return '#ea3324';
        } else if(states["sensor.purpleair_dewpoint"].state > 65){
          return '#ef8533';
        } else if(states["sensor.purpleair_dewpoint"].state > 60){
          return '#ffff55';
        } else if(states["sensor.purpleair_dewpoint"].state > 55){
          return '#68c843';
        } else if(states["sensor.purpleair_dewpoint"].state > 50){
          return '#68fa43';
        } else if(states["sensor.purpleair_dewpoint"].state > 30){
          return '#34bdeb';
        } else if(states["sensor.purpleair_dewpoint"].state > 0){
          return '#0513eb';
        } else{
          return '#0000ff';
        }
      ]]]
  - type: 'custom:canvas-gauge-card'
    card_height: 300
    entity: sensor.purpleair_dewpoint
    name: ''
    gauge:
      type: radial-gauge
      title: Dewpoint
      width: 300
      height: 300
      minValue: 0
      maxValue: 100
      startAngle: 40
      ticksAngle: 280
      valueBox: true
      majorTicks:
        - 0
        - 5
        - 10
        - 15
        - 20
        - 25
        - 30
        - 35
        - 40
        - 45
        - 50
        - 55
        - 60
        - 65
        - 70
        - 75
        - 80
        - 85
        - 90
        - 95
        - 100
      minorTicks: 5
      strokeTicks: true
      highlights:
        - from: 0
          to: 30
          color: 'rgba(5, 19, 235, .75)'
        - from: 30
          to: 50
          color: 'rgba(52, 189, 235, .75)'
        - from: 50
          to: 55
          color: 'rgba(104, 250, 67, .75)'
        - from: 55
          to: 60
          color: 'rgba(104, 200, 67, .75)'
        - from: 60
          to: 65
          color: 'rgba(255, 255, 85, .75)'
        - from: 65
          to: 70
          color: 'rgba(239, 133, 51, .75)'
        - from: 70
          to: 75
          color: 'rgba(234, 51, 36, .75)'
        - from: 75
          to: 80
          color: 'rgba(140, 26, 75, .75)'
        - from: 80
          to: 100
          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: 0
      valueInt: 0
  - type: 'custom:mini-graph-card'
    entities:
      - sensor.purpleair_dewpoint
    unit: Dewpoint (24hr)
    name: ' '
    icon: blank
    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: '#0513eb'
      - value: 30
        color: '#0513eb'
      - value: 30.1
        color: '#34bdeb'
      - value: 50
        color: '#34bdeb'
      - value: 50.1
        color: '#68fa43'
      - value: 55
        color: '#68fa43'
      - value: 55.1
        color: '#68c843'
      - value: 60
        color: '#68c843'
      - value: 60.1
        color: '#ffff55'
      - value: 65
        color: '#ffff55'
      - value: 65.1
        color: '#ef8533'
      - value: 70
        color: '#ef8533'
      - value: 70.1
        color: '#ea3324'
      - value: 75
        color: '#ea3324'
      - value: 75.1
        color: '#8c1a4b'
      - value: 80
        color: '#8c1a4b'
      - value: 80.1
        color: '#731425'
  - type: 'custom:mini-graph-card'
    entities:
      - sensor.purpleair_dewpoint
    unit: Dewpoint (Year)
    name: ' '
    icon: blank
    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: 8760
    color_thresholds:
      - value: 0
        color: '#0513eb'
      - value: 30
        color: '#0513eb'
      - value: 30.1
        color: '#34bdeb'
      - value: 50
        color: '#34bdeb'
      - value: 50.1
        color: '#68fa43'
      - value: 55
        color: '#68fa43'
      - value: 55.1
        color: '#68c843'
      - value: 60
        color: '#68c843'
      - value: 60.1
        color: '#ffff55'
      - value: 65
        color: '#ffff55'
      - value: 65.1
        color: '#ef8533'
      - value: 70
        color: '#ef8533'
      - value: 70.1
        color: '#ea3324'
      - value: 75
        color: '#ea3324'
      - value: 75.1
        color: '#8c1a4b'
      - value: 80
        color: '#8c1a4b'
      - value: 80.1
        color: '#731425'

UI config for the AQI is in the PurpleAir thread.

I am looking for ideas on what else to do or implement.
If anyone has any questions feel free to ask.
I am not completely set on the terms I used for comfort, so I would like ideas here.
I am debating putting a ‘comfortable’ zone between ‘somewhat dry’ and ‘very comfortable’.
If anyone has ideas as to what zones feel like x, I’m listening.
Does anyone know of any overall comfort descriptions combining various items; such as temperature 75F, dewpoint 54F, AQI 10, and Sunny would be ‘Paradise’. This will get very complicated but I want to put the work into sensors to figure this out to make an easy display.

1 Like

This looks great! I’m going to give this a shot this weekend. I really like the idea of finding indoor comfort level and then making climate decisions based on that value.

I got my dew point template sensors up and running. I’m using a simple formula to approximate it from temperature and RH. I’ll build the thermal comfort sensors off of the dew points, and then retool my thermostat setpoints to be functions of thermal comfort.

I’ve had to blow the dust off my heat transfer book. This has been fun!

I have everything up above, but it is more fun to do it yourself.

I’ll use your numbers for dew point to thermal comfort. Not sure if I will do it in yaml or handle it in node-red.

What ‘feels’ comfortable to you might be different that what it is to me, but it probably won’t be my much. You can tweak as you need. I am interested in what you ultimately come up with.
I have a NEST and have not done the new integration yet with the new API, after more people are successful with it I will import it. With you doing the rest of the leg work, it should help me along my way.

One step closer. I decided to just do all of this in esphome at the multisensors where I’m pulling the data:

Screen Shot 2021-01-13 at 8.55.20 PM