PurpleAir Air Quality Sensor

I’ve been following this thread for a long time and finally got a configuration working well for my local sensor. Some additions from others I’ve seen:

  • Everything in a YAML file so it is easy to tweak and edit.
  • All of the interesting sensors have unique_ids so that they are easy to use in the UI.
  • Nice Unicode strings for the units and friendly names (e.g. µg/m³)
  • US EPA Smoke conversion provided as a separate sensor.
  • Temperature and Humidity offsets applied as documented by Purple Air.
  • Temperature smoothing statistics sensor (because mine seems to be a bit wonky).
2 Likes

I noticed that you get noise (your words); there are at least two different pages for json info for the purpleair. I will have to check when I get home (or look around on here) what it actually is but I think it is “\avg” which will give you the 10 min running average. I use the 10 min running average for all my sensors.

Edit Why are you using slightly different correction constants for you EPA correction?
From the EPA:

PM2.5 corrected= 0.534*[PA_cf1(avgAB)] - 0.0844*RH +5.604

Yours:

{{ 0.52 * ((state_attr('sensor.purpleair','pm2_5_cf_1') + state_attr('sensor.purpleair','pm2_5_cf_1_b')) / 2) - (0.085 * state_attr('sensor.purpleair','current_humidity')) + 5.71 }}

I also like the idea of averaging the two channels together, which I will probably work on updating mine.

Somewhere above I have some other sensors like dewpoint that is calculated from my PA.
I can repost everything here or in your repo if you would like.

@GlennHA this is what my raw temperature readings looked like. Noisy, but not really random, which is why I chose to take the trailing max vs a trailing average.

For the wild fire correction, I used the formula on slide 8 from PurpleAir PM2.5 U.S. Correction and Performance During Smoke Events 4/2020 | Science Inventory | US EPA. Do you know of a more up to date formula?

I went off the link you had in the yaml which is not the same as above. You linked to the 2018 version instead of the 2020 version in that section of the yaml on your repository (just update to the link above).

I read that paper and from my personal experiance with looking at Purple Air map and the EPA AirNow map when compared to just going outside and breathing that the purple air is more acurate than the AirNow map. Also recently for some non-credible reason, the AirNow map forbids itself being used in an iFrame. The paper says that PurpleAir reports correct 80% of the time and only over reports 20% of the time (and only by 1AQI); my experience is that the AirNow map drastically under-reports. There were days when there was no visibility due to smoke from wildfires over a hundred miles away and the AirNow map showed my area as green. I also live less than 20 miles from an EPA test site at an airport.

Do you see any real difference with the calculations for the PurpleAir AQI and the ‘corrected’ AQI?

Are you sure? Maybe I’m drowning in PDFs, but I think the one I had in the YAML and the one I linked above are both the same (ID 349513 from the URL link) and are titled 4/2020. In either case, I cleaned up the one in the YAML to remove the extra junk in the URL from the comment.

I didn’t really notice a difference last year. But my house is in a hilly/mountainous area where it is hard to compare to anything nearby and wide area values aren’t usable.

If you have a dew point value calculation, I’m all ears!

My mistake, PurpleAir has DewPoint built in. I use the calculation on my indoor sensors, but here you go:

- platform: template
  sensors:
    bathroom_master_dewpoint:
      friendly_name: "Bathroom Master Dewpoint"
      value_template: >-
        {% set h = states('sensor.bathmaster_multisensor_humidity_air') | float(default=0) %}
        {% set t = states('sensor.bathmaster_multisensor_temperature_air') | float(default=0) %}
        {{((t-32)*5/9-(100-h)/5)*9/5+32}}
      unit_of_measurement: "F"

Here is my mostly complete PA in HA:

- platform: rest
  name: 'PurpleAir'
  resource: http://10.74.1.198/json?live=false
  value_template: '{{ value_json.SensorId }}'
  scan_interval: 120
  json_attributes:
    #- Mem
    #- memfrag
    - uptime
    - rssi
    #- Adc
    - current_temp_f
    - current_humidity
    - current_dewpoint_f
    - pressure
    - p_0_3_um
    - p_0_3_um_b
    - p_0_5_um
    - p_0_5_um_b
    - p_1_0_um
    - p_1_0_um_b
    - pm1_0_atm
    - pm1_0_atm_b
    - p_2_5_um
    - p_2_5_um_b
    - pm2_5_atm
    - pm2_5_atm_b
    - p_5_0_um
    - p_5_0_um_b
    - p_10_0_um
    - p_10_0_um_b
    - pm10_0_atm
    - pm10_0_atm_b
    - pm2.5_aqi
    - pm2.5_aqi_b
- platform: template
  sensors:
   # purpleair_memory:
   #   friendly_name: "PurpleAir Memory"
   #   value_template: '{{ states.sensor.purpleair.attributes["Mem"] }}'
   # purpleair_adc:
   #   friendly_name: "PurpleAir ADC"
   #   value_template: '{{ states.sensor.purpleair.attributes["Adc"] }}'
    purpleair_uptime:
      friendly_name: "PA Uptime"
      value_template: '{{ states.sensor.purpleair.attributes["uptime"] }}'
      unit_of_measurement: "seconds"
   # purpleair_memory_fragmentation:
   #   friendly_name: "PurpleAir Memory Fragmentation"
   #   value_template: '{{ states.sensor.purpleair.attributes["memfrag"] }}'
    purpleair_wifi_rssi:
      friendly_name: "PA Wifi RSSI"
      value_template: '{{ states.sensor.purpleair.attributes["rssi"] }}'
      device_class: signal_strength
    purpleair_temp:
      friendly_name: "PA Temperature"
      value_template: '{{ states.sensor.purpleair.attributes["current_temp_f"] }}'
      unit_of_measurement: "F"
      device_class: temperature
    purpleair_humidity:
      friendly_name: "PA Humidity"
      value_template: '{{ states.sensor.purpleair.attributes["current_humidity"] }}'
      unit_of_measurement: "%"
      device_class: humidity
    purpleair_dewpoint:
      friendly_name: "PA Dewpoint"
      value_template: '{{ states.sensor.purpleair.attributes["current_dewpoint_f"] }}'
      unit_of_measurement: "F"
      device_class: temperature
    purpleair_pressure:
      friendly_name: "PA Pressure"
      value_template: '{{ states.sensor.purpleair.attributes["pressure"] }}'
      unit_of_measurement: "mbar"
      device_class: pressure
    purpleair_aqi_a:
      friendly_name: "PA AirQuality A"
      value_template: '{{ states.sensor.purpleair.attributes["pm2.5_aqi"] }}'
      unit_of_measurement: "AQI"
    purpleair_aqi_b:
      friendly_name: "PA AirQuality B"
      value_template: '{{ states.sensor.purpleair.attributes["pm2.5_aqi_b"] }}'
      unit_of_measurement: "AQI"
    purpleair_p_0_3_um_a:
      friendly_name: "PA .3um Partical Count A"
      value_template: '{{ states.sensor.purpleair.attributes["p_0_3_um"] }}'
      unit_of_measurement: "um/dl"
    purpleair_p_0_3_um_b:
      friendly_name: "PurpleAir .3um Partical Count B"
      value_template: '{{ states.sensor.purpleair.attributes["p_0_3_um_b"] }}'
      unit_of_measurement: "um/dl"
    purpleair_p_0_5_um_a:
      friendly_name: "PA .5um Partical Count A"
      value_template: '{{ states.sensor.purpleair.attributes["p_0_5_um"] }}'
      unit_of_measurement: "um/dl"
    purpleair_p_0_5_um_b:
      friendly_name: "PA .5um Partical Count B"
      value_template: '{{ states.sensor.purpleair.attributes["p_0_5_um_b"] }}'
      unit_of_measurement: "um/dl"
    purpleair_p_1_0_um_a:
      friendly_name: "PA 1.0um Partical Count A"
      value_template: '{{ states.sensor.purpleair.attributes["p_1_0_um"] }}'
      unit_of_measurement: "um/dl"
    purpleair_p_1_0_um_b:
      friendly_name: "PA 1.0um Partical Count B"
      value_template: '{{ states.sensor.purpleair.attributes["p_1_0_um_b"] }}'
      unit_of_measurement: "um/dl"
    purpleair_p_2_5_um_a:
      friendly_name: "PA 2.5um Partical Count A"
      value_template: '{{ states.sensor.purpleair.attributes["p_2_5_um"] }}'
      unit_of_measurement: "um/dl"
    purpleair_p_2_5_um_b:
      friendly_name: "PA 2.5um Partical Count B"
      value_template: '{{ states.sensor.purpleair.attributes["p_2_5_um_b"] }}'
      unit_of_measurement: "um/dl"
    purpleair_p_5_0_um_a:
      friendly_name: "PA 5.0um Partical Count A"
      value_template: '{{ states.sensor.purpleair.attributes["p_5_0_um"] }}'
      unit_of_measurement: "um/dl"
    purpleair_p_5_0_um_b:
      friendly_name: "PA 5.0um Partical Count B"
      value_template: '{{ states.sensor.purpleair.attributes["p_5_0_um_b"] }}'
      unit_of_measurement: "um/dl"
    purpleair_p_10_0_um_a:
      friendly_name: "PA 10.0um Partical Count A"
      value_template: '{{ states.sensor.purpleair.attributes["p_10_0_um"] }}'
      unit_of_measurement: "um/dl"
    purpleair_p_10_0_um_b:
      friendly_name: "PA 10.0um Partical Count B"
      value_template: '{{ states.sensor.purpleair.attributes["p_10_0_um_b"] }}'
      unit_of_measurement: "um/dl"
    purpleair_pm10_atm_a:
      friendly_name: "PA 10.0um Mass A"
      value_template: '{{ states.sensor.purpleair.attributes["pm10_0_atm"] }}'
      unit_of_measurement: "ug/m3"
    purpleair_pm10_atm_b:
      friendly_name: "PA 10.0um Mass B"
      value_template: '{{ states.sensor.purpleair.attributes["pm10_0_atm_b"] }}'
      unit_of_measurement: "ug/m3"
    purpleair_pm1_atm_a:
      friendly_name: "PA 1.0um Mass A"
      value_template: '{{ states.sensor.purpleair.attributes["pm1_0_atm"] }}'
      unit_of_measurement: "ug/m3"
    purpleair_pm1_atm_b:
      friendly_name: "PA 1.0um Mass B"
      value_template: '{{ states.sensor.purpleair.attributes["pm1_0_atm_b"] }}'
      unit_of_measurement: "ug/m3"
    purpleair_pm2_5_atm_a:
      friendly_name: "PA 2.5um Mass A"
      value_template: '{{ states.sensor.purpleair.attributes["pm2_5_atm"] }}'
      unit_of_measurement: "ug/m3"
    purpleair_pm2_5_atm_b:
      friendly_name: "PA 2.5um Mass B"
      value_template: '{{ states.sensor.purpleair.attributes["pm2_5_atm_b"] }}'
      unit_of_measurement: "ug/m3"
    purpleair_description:
      friendly_name: 'PA AQI Description'
      unique_id: purpleair_description
      value_template: >
        {% set aqi = states('sensor.purpleair_aqi_a')|float(default=0) %}
        {% if aqi >= 401.0 %}
          Very Hazardous
        {% elif aqi >= 301.0 %}
          Hazardous
        {% elif aqi >= 201.0 %}
          Very Unhealthy
        {% elif aqi >= 151.0 %}
          Unhealthy
        {% elif aqi >= 101.0 %}
          Unhealthy for Sensitive Groups
        {% elif aqi >= 51.0 %}
          Moderate
        {% elif aqi >= 0.0 %}
          Good
        {% else %}
          {{states('sensor.purpleair_description')}}
        {% endif %}
      entity_id: sensor.purpleair
      #availability_template: '{{ not is_state("sensor.purpleair", "unavailable") }}'

1 Like

Wow, I never realized that the sensor had dew point and pressure.

But I went down a bit of a rabbit hole. I had a hunch that the built-in dew point was based on the raw values without the suggested corrections. I did some math and confirmed that to be the case. I also realized that the simplified formula was way off for the currently dry air I’m experiencing. So, I implemented a more complete formula. I don’t know if this is right, but it seems to produce a reasonable value. :man_shrugging:

Updates in GitHub.

There has been a lot of additions to the device class selections since I set mine up. None of the air quality related items where there before.

This may give you some ideas:
https://github.com/GlennGoddard/CanvasGaugeBackgrounds

I would also add all the sensors to your yaml, even if you don’t use them, just to help keep track of them. I’m referring to wifi signal, memory fragmentation, etc…; I have them and just comment out the ones I don’t see a need for.

I have a Weather Station and I find that that, at least for my location, the dewpoint from PurpleAir and my simplified formula work fairly well.
I also like the description of air quality, which is at the bottom of my yaml, this makes Text-To-Speech (TTS) and phone notifications more useful. If lights are on in a room then the speaker will anouce any change in air quality from one band to another. Everything is self hosted, my speakers are just RPi with a USB speaker running KODI. I use MaryTTS for the speech and this setup has been working great for a few years now.

I pulled some of my calculations out of my PurpleAir setup once I got my Tempest Weather Station but you might find some useful calculations here:
https://github.com/briis/hass-weatherflow2mqtt

I’m attempting to locally import multiple PurpleAir’s into HA, but I seem to be unable to figure out why this code is not working. The code works fine if I try to import just the humidity from one sensor, but if I try adding a second one like shown below, it fails to work.

  - platform: rest
    name: "PurpleAir"
    resource: http://10.140.150.160/json?live=true
    value_template: "91:yb:at:12:42:ef"
    json_attributes:
      - current_humidity

  - platform: template
    sensors:
      purpleair_humidity:
        friendly_name: "PurpleAir Indoor Humidity"
        value_template: '{{ states.sensor.purpleair.attributes["current_humidity"] }}'
        unit_of_measurement: "%"

  - platform: rest
    name: "PurpleAir"
    resource: http://10.140.150.161/json?live=true
    value_template: "48:3g:da:88:1c:46"
    json_attributes:
      - current_humidity

  - platform: template
    sensors:
      purpleair_humidity:
        friendly_name: "PurpleAir Outdoor Humidity"
        value_template: '{{ states.sensor.purpleair.attributes["current_humidity"] }}'
        unit_of_measurement: "%"

Does anyone have any ideas of how I can import two PurpleAir’s into HA?

Use the example 3 posts up and just change the name and the IP address to differentiate.

I’m not sure about your value_template and you have reuse the same name a few times.

I ultimately ended up using Home Assistant’s NodeRed integration to get both sensors working. I spent many countless hours setting this NodeRed configuration up so I figured I would post it here to save someone the time in the future if they plan to use something like this.

Here is a complete list for the outdoor PurpleAir, the indoor PurpleAir (which I recieved today) had slightly different ‘sensors’.

Uncomment if desired. I have yet to figure out all the items.

### PurpleAir Local Outside
- platform: rest
  name: 'PurpleAir'
  resource: http://10.74.1.198/json?live=false
  value_template: '{{ value_json.SensorId }}'
  scan_interval: 120
  json_attributes:
    #- SensorId
    #- DateTime
    #- Geo
    #- Mem
    #- memfrag
    #- memfb
    #- memcs
    #- Id
    #- lat
    #- log
    #- Adc
    #- loggingrate
    #- place
    #- version
    - uptime
    - rssi
    #- period
    #- httpsuccess
    #- httpsends
    #- hardwareversion
    #- hardwarediscovered
    - current_temp_f
    - current_humidity
    - current_dewpoint_f
    - pressure
    - p25aqic_b
    - pm2.5_aqi_b
    - pm1_0_cf_1_b
    - p_0_3_um_b
    - pm2_5_cf_1_b
    - p_0_5_um_b
    - pm10_0_cf_1_b
    - p_1_0_um_b
    - pm1_0_atm_b
    - p_2_5_um_b
    - pm2_5_atm_b
    - p_5_0_um_b
    - pm10_0_atm_b
    - p_10_0_um_b
    - p25aqic
    - pm2.5_aqi
    - pm1_0_cf_1
    - p_0_3_um
    - pm2_5_cf_1
    - p_0_5_um
    - pm10_0_cf_1
    - p_1_0_um
    - pm1_0_atm
    - p_2_5_um
    - pm2_5_atm
    - p_5_0_um
    - pm10_0_atm
    - p_10_0_um
    #- pa_latency
    #- response
    #- response_date
    #- latency
    #- key1_response
    #- key1_response_date
    #- key1_count
    #- ts_latency
    #- key2_response
    #- key2_response_date
    #- key2_count
    #- ts_s_latency
    #- key1_response_b
    #- key1_response_date_b
    #- key1_count_b
    #- ts_latency_b
    #- key2_response_b
    #- key2_response_date_b
    #- key2_count_b
    #- ts_s_latency_b
    #- wlstate
    #- status_0
    #- status_1
    #- status_2
    #- status_3
    #- status_4
    #- status_5
    #- status_6
    #- status_7
    #- status_8
    #- status_9
    #- ssid

Below are the Indoor PA options:

    #- SensorId
    #- DateTime
    #- Geo
    #- Mem
    #- memfrag
    #- memfb
    #- memcs
    #- Id
    #- lat
    #- lon
    #- Adc
    #- loggingrate
    #- place
    #- version
    - uptime
    - rssi
    #- period
    #- httpsuccess
    #- httpsends
    #- hardwareversion
    #- hardwarediscovered
    - current_temp_f
    - current_humidity
    - current_dewpoint_f
    - pressure
    #- p25aqic
    - pm2.5_aqi
    - pm1_0_cf_1
    - p_0_3_um
    - pm2_5_cf_1
    - p_0_5_um
    - pm10_0_cf_1
    - p_1_0_um
    - pm1_0_atm
    - p_2_5_um
    - pm2_5_atm
    - p_5_0_um
    - pm10_0_atm
    - p_10_0_um
    #- pa_latency
    #- key1_response
    #- key1_response_date
    #- key1_count
    #- ts_latency
    #- key2_response
    #- key2_response_date
    #- key2_count
    #- ts_s_latency
    #- key1_response_b
    #- key1_response_date_b
    #- key1_count_b
    #- ts_latency_b
    #- wlstate
    #- status_0
    #- status_1
    #- status_2
    #- status_3
    #- status_4
    #- status_5
    #- status_7
    #- status_8
    #- status_9
    #- ssid
2 Likes

To anyone interested in purchasing an indoor and an outdoor sensor, I would highly recommend purchasing two outdoor sensors instead of an indoor sensor and an outdoor sensor. The indoor sensor is not nearly as accurate as the outdoor sensor.

I’ll be returning my indoor sensor and replacing it with an outdoor sensor. So I’ll have 2 outdoor sensors, but one will be used indoors and one will be used outdoors.

Source relating to the inferiority of the indoor sensor: http://www.aqmd.gov/docs/default-source/aq-spec/summary/purple-air-pa-i-indoor---summary-report.pdf?sfvrsn=20

1 Like

Sure, post this the day after I get my indoor.

1 Like

No worries GlennHA, I did the same thing. I personally contacted PurpleAir and they were more than willing to exchange the indoor sensor for the outdoor sensor. It came out to about an extra $60 that I had to pay them for the price difference between the two sensors which I believe is completely worth it.

I’ve finally got the PurpleAir Outdoor sensor incorporated into HA in a very nice manner that looks decent.

The PM2.5 colors are pulled directly from PurpleAir’s JSON file as well so it updates the color-codes perfectly.

If anyone is interested in using this, here is the HA Lovelave code (requires my NodeRed code to pull in the data as I linked above):

type: vertical-stack
title: PurpleAir Outdoor Sensor's
cards:
  - type: horizontal-stack
    cards:
      - entity: sensor.purpleair_outdoor_aqi_2_5_120s_moving_average_a
        color: black;
        scale: 35px
        title: PM2.5 (A)
        type: custom:bignumber-card
        noneCardClass: custom:bignumber-card
        style: |
          ha-card {
            background: {{ states('sensor.purpleair_outdoor_pm_2_5_aqi_rgb_color_a') }}

                         }  
      - entity: sensor.purpleair_outdoor_aqi_2_5_120s_moving_average_b
        color: black;
        scale: 35px
        title: PM2.5 (B)
        type: custom:bignumber-card
        noneCardClass: custom:bignumber-card
        style: |
          ha-card {
            background: {{ states('sensor.purpleair_outdoor_pm_2_5_aqi_rgb_color_b') }}

                         }  
  - type: horizontal-stack
    cards:
      - type: custom:stack-in-card
        cards:
          - type: custom:button-card
            name: PM1.0 (µg/m3)
          - entity: sensor.purpleair_outdoor_1_0um_mass_a
            title: 'Sensor: A'
            scale: 20px
            type: custom:bignumber-card
            hideunit: true
            noneCardClass: custom:bignumber-card
          - entity: sensor.purpleair_outdoor_1_0um_mass_b
            title: 'Sensor: B'
            scale: 20px
            type: custom:bignumber-card
            hideunit: true
            noneCardClass: custom:bignumber-card
      - type: custom:stack-in-card
        cards:
          - type: custom:button-card
            name: PM2.5 (µg/m3)
          - entity: sensor.purpleair_outdoor_2_5um_mass_a
            title: 'Sensor: A'
            scale: 20px
            type: custom:bignumber-card
            hideunit: true
            noneCardClass: custom:bignumber-card
          - entity: sensor.purpleair_outdoor_2_5um_mass_b
            title: 'Sensor: B'
            scale: 20px
            type: custom:bignumber-card
            hideunit: true
            noneCardClass: custom:bignumber-card
      - type: custom:stack-in-card
        cards:
          - type: custom:button-card
            name: PM10 (µg/m3)
          - entity: sensor.purpleair_outdoor_10_0um_mass_a
            title: 'Sensor: A'
            scale: 20px
            type: custom:bignumber-card
            hideunit: true
            noneCardClass: custom:bignumber-card
          - entity: sensor.purpleair_outdoor_10_0um_mass_b
            title: 'Sensor: B'
            scale: 20px
            type: custom:bignumber-card
            hideunit: true
            noneCardClass: custom:bignumber-card
  - type: custom:stack-in-card
    cards:
      - type: custom:button-card
        name: Partical Counter (particles/deciliter)
  - type: horizontal-stack
    cards:
      - type: custom:stack-in-card
        cards:
          - type: custom:button-card
            name: '>=0.3µm'
          - entity: sensor.purpleair_outdoor_3um_partical_count_a
            title: 'Sensor: A'
            scale: 12px
            type: custom:bignumber-card
            hideunit: true
            noneCardClass: custom:bignumber-card
          - entity: sensor.purpleair_outdoor_3um_partical_count_b
            title: 'Sensor: B'
            scale: 12px
            type: custom:bignumber-card
            hideunit: true
            noneCardClass: custom:bignumber-card
      - type: custom:stack-in-card
        cards:
          - type: custom:button-card
            name: '>=0.5µm'
          - entity: sensor.purpleair_outdoor_5um_partical_count_a
            title: 'Sensor: A'
            scale: 12px
            type: custom:bignumber-card
            hideunit: true
            noneCardClass: custom:bignumber-card
          - entity: sensor.purpleair_outdoor_5um_partical_count_b
            title: 'Sensor: B'
            scale: 12px
            type: custom:bignumber-card
            hideunit: true
            noneCardClass: custom:bignumber-card
      - type: custom:stack-in-card
        cards:
          - type: custom:button-card
            name: '>=1.0µm'
          - entity: sensor.purpleair_outdoor_1_0um_partical_count_a
            title: 'Sensor: A'
            scale: 12px
            type: custom:bignumber-card
            hideunit: true
            noneCardClass: custom:bignumber-card
          - entity: sensor.purpleair_outdoor_1_0um_partical_count_b
            title: 'Sensor: B'
            scale: 12px
            type: custom:bignumber-card
            hideunit: true
            noneCardClass: custom:bignumber-card
      - type: custom:stack-in-card
        cards:
          - type: custom:button-card
            name: '>=2.5µm'
          - entity: sensor.purpleair_outdoor_2_5um_partical_count_a
            title: 'Sensor: A'
            scale: 12px
            type: custom:bignumber-card
            hideunit: true
            noneCardClass: custom:bignumber-card
          - entity: sensor.purpleair_outdoor_2_5um_partical_count_b
            title: 'Sensor: B'
            scale: 12px
            type: custom:bignumber-card
            hideunit: true
            noneCardClass: custom:bignumber-card
      - type: custom:stack-in-card
        cards:
          - type: custom:button-card
            name: '>=5.0µm'
          - entity: sensor.purpleair_outdoor_5_0um_partical_count_a
            title: 'Sensor: A'
            scale: 12px
            type: custom:bignumber-card
            hideunit: true
            noneCardClass: custom:bignumber-card
          - entity: sensor.purpleair_outdoor_5_0um_partical_count_b
            title: 'Sensor: B'
            scale: 12px
            type: custom:bignumber-card
            hideunit: true
            noneCardClass: custom:bignumber-card
      - type: custom:stack-in-card
        cards:
          - type: custom:button-card
            name: '>=10µm'
          - entity: sensor.purpleair_outdoor_10_0um_partical_count_a
            title: 'Sensor: A'
            scale: 12px
            type: custom:bignumber-card
            hideunit: true
            noneCardClass: custom:bignumber-card
          - entity: sensor.purpleair_outdoor_10_0um_partical_count_b
            title: 'Sensor: B'
            scale: 12px
            type: custom:bignumber-card
            hideunit: true
            noneCardClass: custom:bignumber-card

1 Like

I wonder if there is a way to remove some majorTicks but still have the colors fitting to the ticks (and as I assume the pointer pointing to the correct values)?
My idea is to strech the lower intervals and compress the bigger intervals because nobody cares if it is 360 or 390.
grafik

type: custom:mod-card
card_mod:
  class: top-level-graph
card:
  type: custom:canvas-gauge-card
  entity: sensor.pm2_5
  gauge:
    type: radial-gauge
    title: Feinstaub 2.5
    width: 230
    height: 230
    minValue: 0
    maxValue: 500
    startAngle: 40
    ticksAngle: 280
    valueBox: true
    majorTicks:
      - '0'
      - '50'
      - '100'
      - '150'
      - '200'
      - '300'
      - '500'
    minorTicks: 5
    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: 0
    valueInt: null

You can change the major ticks and change the maxValue to anything you want.

Did so.
But why are the colors not fitting to the numbers or vice versa?
And the pointer seems to be wrong, too.
In the picture above the 50 is in the yellow area although it should be green.

      - from: 0
        to: 50
        color: rgba(104, 225, 67, .75)
``

The major ticks must be equally apart, so you can’t skip numbers. It would appear you can in the documentation, but in practice I’ve not ever been able to get it to work without equidistant numbers.