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)
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
- a structured JSON error payload on
- 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(runruff format --check .andruff 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file montreal_aqi_api-0.5.0.tar.gz.
File metadata
- Download URL: montreal_aqi_api-0.5.0.tar.gz
- Upload date:
- Size: 17.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2ba7bd7e98fca8e6d160b30b6ca6116b7db3ee7ec09d7913ef73808a00c47980
|
|
| MD5 |
7fe237823e98530c859913daba51fe15
|
|
| BLAKE2b-256 |
dfeb57b0e3a025de86a7f4c46766390aa6007e5ad2bfc828f2a061999bc4e99b
|
File details
Details for the file montreal_aqi_api-0.5.0-py3-none-any.whl.
File metadata
- Download URL: montreal_aqi_api-0.5.0-py3-none-any.whl
- Upload date:
- Size: 14.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a464794b407a0086ed8ecdc2fb101c964c31685fc8f287f13a37c4f37e046240
|
|
| MD5 |
9c5a73e0224686b200fcbdb306a5e9c9
|
|
| BLAKE2b-256 |
5cdbe8f71fdafb236e8f0f03a734ccaf36bfb796bc619bf6fb117408dee50057
|