A no-nonsense Android app & widgets for displaying Canadian Air Quality Health Index (AQHI) conditions, alerts, forecasts and historical readings.
Download and install the latest release.
Features:
- View the latest air quality readings from the nearest monitoring station to your location.
- See AQHI forecasts for the next several days.
- Receive alerts when ECCC issues warnings for your selected area.
- Explore daily and hourly trends, including median “typical” values based on a 10-year analysis of air quality data.
- View air pollution maps for NO2, NO, O3, SO2, PM 2.5, PM 10, and wildfire smoke.
- Choose from three configurable home screen widgets to monitor AQHI at a glance.
- Automatically switches between light and dark mode based on your system settings.
- Maps are entirely offline, with no location data sent to any server.
Note
Both light mode and dark mode are supported and will switch automatically with the system preference.
Tip
Tapping on the heat maps reveals the raw data values!
Interactive pollution maps are available for all of Canada for NO2, NO, O3, SO2, PM 2.5, PM 10, and wildfire smoke. The map overlays are updated hourly and represent the most recent observations (1-3 hour delay) based on the RDAQA air quality analysis model from Environment and Climate Change Canada (ECCC) .
Tip
Tapping on the scale changes the colour gradient of the overlay.
Three widgets are provided: a small widget that displays the most recent AQHI reading at your location, a larger, wider widget that shows the AQHI reading on a relative scale, and a fun emoji smiley face widget that changes with the current AQHI reading.
Widgets are configurable: you can set the background transparency as well as the light/dark mode. A preview of the widget is shown as you configure it.
Tip
Setting light/dark mode to automatic will make the widget switch automatically with the system preference.
Alerts are displayed in the main app and in the large widget whenever Environment and Climate Change Canada (ECCC) issues a public air quality alert for your currently selected station. These are colour coded based on ECCC's severity scale: Warning (red), Watch (yellow), and Statement (grey).
AQHI Data is pulled from Environment and Climate Change Canada's public API using the closest active monitoring station to your current location. The station definitions, current location, and current AQHI readings are all cached to prevent excessive calls to the API. Data is shared between the main app and the widgets.
The typical AQHI is calculated as the median hourly AQHI for the current hour of the day and current week of the year, based on data from your selected location. This calculation uses a 10-year period from 2014 to 2023, where at least 5 years of data are available for that location.
These values were generated using my NAPS Data Analysis Toolbox, which sources raw data from the National Air Pollution Surveillance (NAPS) program, part of Environment and Climate Change Canada. I calculated the tables for the median AQHI from the raw concentration readings of the 3 constituent pollutants (O3, NO2, & PM2.5) for all roughly 300 current active NAPS sites. These sites are then matched to the correct GeoMet stations using a bit of fuzzy logic with the latitude and longitude coordinates that both data sets provide. The formula for calculating AQHI is the following:
Typical AQHI data is provided by David Fortin under the terms of the MIT License.
The base map used for viewing and selecting locations, as well as for the pollution map, is stored entirely on-device, as I do not want to send your location off-device.
The map uses the Lambert Conformal Conic projection, which minimizes distortion across Canada. Latitude and longitude pairs are first projected using the Lambert projection constants, and then an affine transformation is applied using 3 well spaced control points to account for the scaling and rotation of the map.
The base map data comes from CBCT3978, which is freely provided by Natural Resources Canada under the terms of the Canadian Open Government Licence. I cleaned up visible JPEG compression artifacts using a neural filter, then manually stitched together the tiles into a single 1-gigapixel image (35,000 × 30,000 pixels). This high-resolution map was then tiled into 8 zoom levels and compressed in WebP format. The result is a folder structure containing approximately 21,500 files, taking up only about 160MB of space.
The map is displayed in the app using Pierre Laurence's MapView library. Check out his project!
Pollution overlays are processed entirely on-device from raw data obtained from the public Datamart of the Meteorological Service of Canada division of Environment and Climate Change Canada. This was no easy feat!
For each pollutant, the directory structure of MSC Datamart is traversed to find the most recent RDAQA geospatial data. This is done because the data is not (yet) available as a REST API, only as an HTTP directory listing. The geospatial metadata is cached on the device to ensure that the data is never downloaded more than once. The geospatial data is downloaded as a file in GRIB2 format.
GRIB2 is a binary format used primarily in the meteorological world. Since I could not find a modern, lightweight native Java library to parse Grib2 files, I wrote my own parser based on the NOAA file specifications. Within the GRIB2 container, the geospatial data is encoded as an image in JPEG 2000 format. JPEG 2000 is now considered a defunct format and modern devices do not natively support decoding it, therefore I compile the OpenJpeg C library to Android native code (armeabi-v7a, arm64-v8a, x86, x86_64) and invoke it from C code, which itself is invoked from Java via JNI. The resulting decompressed raw image data is saved to the file system app cache directory. Previously downloaded data is periodically checked and purged from the file system after it expires.
In order to render the pollution overlay on top of the base map imagery, each pixel of the individual tiles of the map view port are first transformed with an inverse affine transformation and then an inverse Lambert conformal conic projection. This translates the x,y pixel coordinates of the Lambert-projected base map into latitude & longitude coordinates corresponding to the projection of the decompressed pollution imagery. A rotation is applied to the coordinates and a lookup is performed to determine the pollution concentration. Bilinear sampling is applied as part of the lookup to smooth out the hard edges of the pollution overlay. The resulting concentration value is colour-blended into the base map imagery based on the chosen colour scale. Once each tile is computed, it is compressed to WebP lossless format, which generally produces both the smallest files sizes and the fastest compression time on modern Android devices. Up to 512 of these 256x256 pixel WebP-compressed files are cached in memory to provide a more responsive scrolling experience on the map.
A lot of care was taken to optimize the performance of all this image manipulation and math-heavy data processing. The result is that forecasts and observations for NO2, NO, O3, SO2, PM 2.5, PM 10, and wildfire smoke, are all processed entirely on-device, instead of the more typical server-side processing.
The rendering of heat maps is entirely written from scratch by myself. My GitHub project contains rendering libraries for both Android and Java2D. Check it out if you want to add beautiful, customizable heat maps to you own Java project.
Android no longer allows background location access to be enabled by default. If your AQHI location is set to Automatic and you want your homescreen widgets to update automatically while travelling, you’ll need to manually choose “Allow all the time” in the app’s location permission settings. This step is optional.

By default, Android optimizes background activity to extend battery life. However, this can sometimes delay or block widget updates. To ensure AQHI data updates consistently in the background, set the app’s battery usage to “Unrestricted” in the Android battery settings.

The Canadian Air Quality Health Index (AQHI) is a made-in-Canada scale developed by Environment and Climate Change Canada (ECCC) to provide real-time information about the health risks associated with air pollution. It combines measurements from ground-level ozone, fine particulate matter (PM2.5), and nitrogen dioxide into a single numerical value on a scale from 1 (low risk) to 10 (high risk). All values above 10 are assigned a reading of 11+, indicating a very high risk.
Scale:
- 1-3 Low health risk
- 4-6 Moderate health risk
- 7-10 High health risk
- 11+ Very high health risk
As per ECCC, the calculation of the AQHI may change over time to reflect new understanding associated with air pollution health effects. AQHI values are calculated automatically using observations from a network of air quality monitoring stations across Canada. These measurements are collected in real-time and are not verified prior to publication. Forecast and historical AQHI values are reported on an hourly basis.
Real-time, historical and forecast AQHI data is provided by the MSC GeoMet OpenAPI service of the Meteorological Service of Canada (MSC) branch of Environment and Climate Change Canada (ECCC), a department of the Government of Canada. The data is licensed under the terms of the Environment and Climate Change Canada Data Servers End-use Licence and the Canadian Open Government Licence.
For more information about the AQHI, visit ECCC's website.
If you are interested in the analysis of Canadian air quality data that has been validated, check out my NAPS Data Analysis Project on GitHub.
- This app was developed for and tested on Android 14.
This app is made by David Fortin, an individual - not a corporation. It does not collect or share any of your personal information or data.
Your device's location is used only to identify the closest air quality monitoring station, and only if you explicitly grant the app permission to use location services. Your location information stays exclusively on your device and is never transmitted or shared.
This app determines your nearest air quality monitoring station by comparing your location (locally, on your device) with a list of stations obtained from Environment and Climate Change Canada's (ECCC) GeoMet service. Your location data is never sent to ECCC or any other server.
You can learn more about ECCC's GeoMet service here.
Copyright (c) 2024 David Fortin
This software is provided by David Fortin under the terms of the MIT License, meaning you are free to use it however you want, as long as you include the original copyright notice (above) and license notice in any copy you make. You just can't hold me liable in case something goes wrong. License details can be read here.
Realtime, historical and forecast AQHI data is provided by the MSC GeoMet OpenAPI service of the Meteorological Service of Canada (MSC) branch of Environment and Climate Change Canada (ECCC), a department of the Government of Canada. Pollution overlay data is provided by the MSC Datamart service of MSC. The data is licensed under the terms of the Environment and Climate Change Canada Data Servers End-use Licence and the Canadian Open Government Licence.
Base map data is provided by Natural Resources Canada, a department of the Government of Canada, also licensed under the terms of the Canadian Open Government Licence.
Typical AQHI data is provided by David Fortin under the terms of the MIT License.