Skip to main content

CLI and Python API to fetch air quality index (AQI) data from the Montreal open data portal

Project description

AQI monitoring for the city of Montréal (Québec, Canada)

Latest Release Python CI Test Coverage PyPI Downloads License Code style: Ruff

A Python library and CLI tool to fetch, process, and expose air quality index (AQI) data from the City of Montréal open data platform.

The project is designed to be:

  • scriptable (JSON output by default)
  • embeddable as a Python library
  • suitable for automation (Home Assistant, cron jobs, data pipelines)

Features

  • Fetches the latest air quality data from Montréal’s open data portal
  • Lists currently active air quality monitoring stations
  • Computes the AQI based on RSQA methodology
  • Estimates pollutant concentrations from reported AQI contributions¹
  • Exposes structured station and pollutant data via Python models
  • Outputs machine-readable JSON from the CLI
  • Structured logging with optional debug mode
  • Test suite covering core logic, JSON contract, and CLI behavior

¹ Estimated concentrations are derived from rounded AQI values and should be treated as approximations.


Requirements

  • Python 3.11 or newer
  • requests

Installation

From PyPI (recommended)

pip install montreal-aqi-api

From source

git clone https://github.com/normcyr/montreal-aqi-api.git
cd montreal-aqi-api
python3 -m venv venv
source venv/bin/activate
pip install .

CLI Usage

The CLI always outputs JSON on stdout. Logs and diagnostics are written to stderr.

Fetch AQI for a specific station

montreal-aqi --station <station_id>

List available monitoring stations

montreal-aqi --list

Enable debug logging

montreal-aqi --station <station_id> --debug

Print the JSON in a pretty format

montreal-aqi --station <station_id> --pretty

or

montreal-aqi --list --pretty

No arguments

If no arguments are provided, the CLI returns a JSON error payload. Interactive prompts are intentionally avoided to keep behavior predictable in automated environments.

Advanced examples

Fetch multiple stations

montreal-aqi --station 1,2,3 --pretty

Suppress output (for scripts)

montreal-aqi --station 80 --quiet
# No output if successful, useful for cron jobs

Verbose logging

montreal-aqi --station 80 --verbose
# Shows detailed logs including API request times and cache status

Combine options

montreal-aqi --list --pretty --verbose

Integrations

This library is designed to be consumed by automated systems and integrations.

Home Assistant

Used by the custom Home Assistant integration:

Other Use Cases

  • Cron jobs
  • Data ingestion pipelines
  • Monitoring dashboards
  • Research / environmental analysis

JSON Contract — Version 1 (Frozen)

As of v0.4.0, the JSON output contract is explicitly versioned and frozen. The output format is formally specified in: docs/json_contract_v1.md.

The JSON output is governed by the official JSON Schema v1 and all payloads include:

{
  "version": 1,
  "type": "..."
}

Error Payload

{
  "version": 1,
  "type": "error",
  "error": {
    "code": "NO_DATA",
    "message": "No data available for this station"
  }
}

Stations List Payload

{
  "version": 1,
  "type": "stations",
  "stations": [
    {
      "station_id": "3",
      "name": "Saint-Jean-Baptiste",
      "borough": "Rivière-des-Prairies"
    }
  ]
}

Station AQI Payload

{
  "version": 1,
  "type": "station",
  "station_id": "80",
  "date": "2025-08-08",
  "hour": 10,
  "aqi": 49,
  "dominant_pollutant": "PM2.5",
  "pollutants": {
    "PM2.5": {
      "name": "PM2.5",
      "aqi": 49,
      "concentration": 34.3
    },
    "O3": {
      "name": "O3",
      "aqi": 22,
      "concentration": 70.4
    }
  }
}

Python Usage

from montreal_aqi_api.service import get_station_aqi

station = get_station_aqi("80")
if station:
    print(station.to_dict())

Domain objects (Station, Pollutant) expose explicit serialization helpers to ease downstream usage.


Exit codes

The montreal-aqi CLI exits with explicit status codes to make it suitable for scripting, automation, and CI pipelines.

Exit code Meaning Description
0 Success Command executed successfully
1 Generic API error An unexpected internal API error occurred
2 API unreachable Montreal Open Data API could not be reached (network error, timeout, DNS, etc.)
3 Invalid API response API returned malformed or unexpected JSON payload

Details

  • All errors are reported both via:
    • a structured JSON error payload on stdout
    • a non-zero process exit code
  • This ensures compatibility with:
    • shell scripts
    • cron jobs
    • CI/CD pipelines
    • Home Assistant / automation tools

Example

$ montreal-aqi --station 80
{
  "version": "1",
  "type": "error",
  "error": {
    "code": "API_UNREACHABLE",
    "message": "Montreal open data API is unreachable"
  }
}

$ echo $?
2

AQI Methodology

AQI values follow the methodology defined by the Réseau de surveillance de la qualité de l’air (RSQA).

Reference Values

Pollutant Full Name Reference
SO₂ Sulfur Dioxide 500 µg/m³
CO Carbon Monoxide 35 mg/m³
O₃ Ozone 160 µg/m³
NO₂ Nitrogen Dioxide 400 µg/m³
PM2.5 Particulate Matter 35 µg/m³

Project Status

  • JSON contract v1 frozen and validated by tests
  • Suitable for automation and integration
  • API stability guaranteed within v1

Contributing

Contributions are welcome.

Please ensure that:

  • tests pass (pytest)
  • the JSON contract remains backward compatible
  • any change affecting output is covered by tests
  • code is linted/formatted with ruff (run ruff format --check . and ruff check .)

Open an issue before proposing breaking changes.


Data Source

Data is retrieved from the Ville de Montréal Open Data Portal.


License

This project is licensed under the MIT License.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

montreal_aqi_api-0.6.1.tar.gz (24.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

montreal_aqi_api-0.6.1-py3-none-any.whl (15.1 kB view details)

Uploaded Python 3

File details

Details for the file montreal_aqi_api-0.6.1.tar.gz.

File metadata

  • Download URL: montreal_aqi_api-0.6.1.tar.gz
  • Upload date:
  • Size: 24.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.14

File hashes

Hashes for montreal_aqi_api-0.6.1.tar.gz
Algorithm Hash digest
SHA256 4df671a5b26e4f644dc1173e4e7482a51101af893a513d96bfcf143bd56f11fe
MD5 a3c5c9fe7e9877f5f58b2122c669be64
BLAKE2b-256 d24302f171807e24507565cfc29da0bf6fc059721ad5b0a5478b604473093fe3

See more details on using hashes here.

File details

Details for the file montreal_aqi_api-0.6.1-py3-none-any.whl.

File metadata

File hashes

Hashes for montreal_aqi_api-0.6.1-py3-none-any.whl
Algorithm Hash digest
SHA256 705a5c96020019464365fe741724a8c35b95e662eaff0a9dfce30fe28c1b43e8
MD5 d39e313fc2d88e7ce9235999f0cfa97e
BLAKE2b-256 5c9c6a60d7d3cfc82b8ab73cad7a01a7219848561a40d1ad0045f384aaf9e595

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page