Track air quality with Home Assistant and EPA data

Loryan Strant
4 min readJul 22, 2023

Before continuing any further, a disclaimer: if you’re expecting this to have any integration with Microsoft 365, stop reading now.
(I mean I probably could, but I haven’t seen a requirement, unless I have some kind of alert sent to Microsoft Teams if the air quality exceeds X threshold, but I digress…)

The Challenge

There are a number of air quality sensors you can buy or build (in fact I’m building one myself using an ESP32 board and PMS5003 sensor, but again I digress…), but there are also a variety of publicly available air quality sensors that can be integrated into Home Assistant.

You can find the list here: Integrations — Home Assistant (

Unfortunately, none of the available services offered sensor data from where I actually live. At best they provided modelling base on satellite data.

The Solution

Thankfully where I live in the state of Victoria, Australia, the Environment Protection Authority provides a service known as “AirWatch” which thankfully both an air quality sensor in my town, as well as a publicly available API.

While the AirWatch website generally shows the quality of air (eg. “Good”, “Fair”, “Poor”, etc.) the API returns the specifics of these metrics — which we can surface in Home Assistant through the use of a RESTful sensor and make it look like this:

Making it work

Getting access to the EPA API

The first step is to sign up for the EPA developer portal which is free to access.

Once signed up, you then need to create a subscription:

You’ll then need to register an application that will communicate with the API:

Once this is done, you’ll now have your key and can start querying the API:

Finding your site ID

In order to return data from API for your location, you need your site ID. And to get your site ID, you need to first query the API with your latitude and longitude for it to return the closest site to your location.

The easiest way to get your latitude and longitude is to browse to Google Maps and have it look up your location. Then use these coordinates in the query:

You can run this query directly from the developer portal.

Getting the initial data

Once you’ve found your site ID, you can then test out querying the API directly. You’ve got two choices here: air monitoring, or air monitoring with scientific parameters.

The first option (air monitoring) will give you the average data over the past 48 hours, whereas the second option (air monitoring with scientific parameters) will give you the same data as well as the hourly results. I opted for the latter.

You can run this query directly from the developer portal.

Putting it into Home Assistant

In our configuration.yaml file, you need to add this text and provide the values for your:

  • Site ID
  • API key
  • Suburb name



- resource:<YOUR SITE ID>/parameters

scan_interval: 1800




- name: "EPA <YOUR SUBURB NAME> Air Quality Hourly Average"

value_template: "{{ value_json['parameters'][0]['timeSeriesReadings'][0]['readings'][0]['averageValue'] }}"

unit_of_measurement: "µg/m³"

state_class: measurement

device_class: pm25

icon: mdi:chemical-weapon

- name: "EPA <YOUR SUBURB NAME> Air Quality Hourly Health Advice"

value_template: "{{ value_json['parameters'][0]['timeSeriesReadings'][0]['readings'][0]['healthAdvice'] }}"

- name: "EPA <YOUR SUBURB NAME> Air Quality Daily Average"

value_template: "{{ value_json['parameters'][0]['timeSeriesReadings'][1]['readings'][0]['averageValue'] }}"

unit_of_measurement: "µg/m³"

state_class: measurement

device_class: pm25

icon: mdi:chemical-weapon

- name: "EPA <YOUR SUBURB NAME> Air Quality Daily Health Advice"

value_template: "{{ value_json['parameters'][0]['timeSeriesReadings'][1]['readings'][0]['healthAdvice'] }}"


The result

What you’ll end up with is four new sensors:

And to display this in a dashboard, we can simply use a gauge card for the current value, and a statistics graph for the historical value:

type: gaugeentity: sensor.epa_sunbury_air_quality_hourly_averagemax: 300needle: trueseverity:green: 0yellow: 100red: 200chart_type: lineperiod: 5minutetype: statistics-graphentities:- sensor.epa_sunbury_air_quality_hourly_averagestat_types:- mean- min- maxhide_legend: true

And that’s that!

This will now update every half hour, and you can use the other sensors in other cards if you like.

I’ve been considering turning this into a HACS custom component but would involve learning Python — and I’m not there yet.

Originally published at Loryan Strant, Microsoft 365 MVP.



Loryan Strant

Microsoft 365 MVP, author, cloud guy, thought opinionater, public speaker, distance gazer. Passionate about productivity and life/work balance.