Skip to main content

Fork of aiopurpleair with extra exception subclasses and the GET /v1/organization endpoint.

Project description

🟣 aiopurpleair: A Python3, asyncio-based library to interact with the PurpleAir API

CI PyPI Version License Code Coverage Maintainability

Buy Me A Coffee

aiopurpleair is a Python3, asyncio-based library to interact with the PurpleAir API.

Installation

pip install aiopurpleair

Python Versions

aiopurpleair is currently supported on:

  • Python 3.10
  • Python 3.11
  • Python 3.12

Usage

In-depth documentation on the API can be found here. Unless otherwise noted, aiopurpleair endeavors to follow the API as closely as possible.

Checking an API Key

To check whether an API key is valid and what properties it has:

import asyncio
from datetime import datetime, timezone

from aiopurpleair import API


async def main() -> None:
    """Run."""
    api = API("<API KEY>")
    response = await api.async_check_api_key()
    # >>> response.api_key_type == ApiKeyType.READ
    # >>> response.api_version == "V1.0.11-0.0.41"
    # >>> response.timestamp_utc == datetime(2022, 10, 27, 18, 25, 41, tzinfo=timezone.utc)


asyncio.run(main())

Getting Sensors

import asyncio
from datetime import datetime, timezone

from aiopurpleair import API


async def main() -> None:
    """Run."""
    api = API("<API_KEY>")
    response = await api.sensors.async_get_sensors(["name"])
    # >>> response.api_version == "V1.0.11-0.0.41"
    # >>> response.data == {
    # >>>     131075: SensorModel(sensor_index=131075, name=Mariners Bluff),
    # >>>     131079: SensorModel(sensor_index=131079, name=BRSKBV-outside),
    # >>> }
    # >>> response.data_timestamp_utc == datetime(2022, 11, 3, 19, 25, 31, tzinfo=timezone.utc)
    # >>> response.fields == ["sensor_index", "name"]
    # >>> response.firmware_default_version == "7.02"
    # >>> response.max_age == 604800
    # >>> response.timestamp_utc == datetime(2022, 11, 3, 19, 26, 29, tzinfo=timezone.utc)


asyncio.run(main())

Method Parameters

  • fields (required): The sensor data fields to include
  • location_type (optional): An LocationType to filter by
  • max_age (optional): Filter results modified within these seconds
  • modified_since (optional): Filter results modified since a UTC datetime
  • read_keys (optional): Read keys for private sensors
  • sensor_indices (optional): Filter results by sensor index

Getting a Single Sensor

import asyncio
from datetime import datetime, timezone

from aiopurpleair import API


async def main() -> None:
    """Run."""
    api = API("<API_KEY>")
    response = await api.sensors.async_get_sensor(131075)
    # >>> response.api_version == "V1.0.11-0.0.41"
    # >>> response.data_timestamp_utc == datetime(2022, 11, 5, 16, 36, 21, tzinfo=timezone.utc)
    # >>> response.sensor == SensorModel(sensor_index=131075, ...),
    # >>> response.timestamp_utc == datetime(2022, 11, 5, 16, 37, 3, tzinfo=timezone.utc)


asyncio.run(main())

Method Parameters

  • sensor_index (required): The sensor index of the sensor to retrieve.
  • fields (optional): The sensor data fields to include.
  • read_key (optional): A read key for a private sensor.

Getting a Private Sensor

Sensors registered as private require their per-sensor read key (visible to the sensor owner from the PurpleAir dashboard). Without it, the API returns NotFoundError even though the sensor exists. Pass the key as read_key= for a single sensor, or as a list to read_keys= when querying multiple sensors at once (the library joins the list with commas before sending):

import asyncio

from aiopurpleair import API


async def main() -> None:
    """Run."""
    api = API("<API_KEY>")

    # Single private sensor
    response = await api.sensors.async_get_sensor(131075, read_key="<SENSOR_READ_KEY>")
    # >>> response.sensor == SensorModel(sensor_index=131075, ...)

    # Multiple sensors, mixing public and private — only the private ones need a key
    response = await api.sensors.async_get_sensors(
        ["name", "pm2.5"],
        sensor_indices=[131075, 131079],
        read_keys=["<SENSOR_READ_KEY_FOR_131075>"],
    )
    # >>> response.data == {131075: ..., 131079: ...}


asyncio.run(main())

Getting Nearby Sensors

This method returns a list of NearbySensorResult objects that are within a bounding box around a given latitude/longitude pair. The list is sorted from nearest to furthest (i.e., the first index in the list is the closest to the latitude/longitude).

NearbySensorResult objects have two properties:

  • sensor: the corresponding SensorModel object
  • distance: the calculated distance (in kilometers) between this sensor and the provided latitude/longitude
import asyncio

from aiopurpleair import API


async def main() -> None:
    """Run."""
    api = API("<API_KEY>")
    sensors = await api.sensors.async_get_nearby_sensors(
        ["name"], 51.5285582, -0.2416796, 10
    )
    # >>> [NearbySensorResult(...), NearbySensorResult(...)]


asyncio.run(main())

Method Parameters

  • fields (required): The sensor data fields to include
  • latitude (required): The latitude of the point to measure distance from
  • longitude (required): The longitude of the point to measure distance from
  • distance (required): The distance from the measured point to search (in kilometers)
  • limit (optional): Limit the results

Getting a Map URL

If you need to get the URL to a particular sensor index on the PurpleAir map website, simply pass the appropriate sensor index to the get_map_url method:

import asyncio

from aiopurpleair import API


async def main() -> None:
    """Run."""
    api = API("<API_KEY>")
    map_url = api.get_map_url(12345)
    # >>> https://map.purpleair.com/1/mAQI/a10/p604800/cC0?select=12345


asyncio.run(main())

Connection Pooling

By default, the library creates a new connection to the PurpleAir API with each coroutine. If you are calling a large number of coroutines (or merely want to squeeze out every second of runtime savings possible), an aiohttp ClientSession can be used for connection pooling:

import asyncio

from aiohttp import ClientSession

from aiopurpleair import API


async def main() -> None:
    """Run."""
    async with ClientSession() as session:
        api = API("<API KEY>", session=session)

        # Get to work...


asyncio.run(main())

Contributing

Thanks to all of our contributors so far!

  1. Check for open features/bugs or initiate a discussion on one.
  2. Fork the repository.
  3. (optional, but highly recommended) Create a virtual environment: python3 -m venv .venv
  4. (optional, but highly recommended) Enter the virtual environment: source ./.venv/bin/activate
  5. Install the dev environment: script/setup
  6. Code your new feature or bug fix on a new branch.
  7. Write tests that cover your new functionality.
  8. Run tests and ensure 100% code coverage: poetry run pytest --cov aiopurpleair tests
  9. Update README.md with any new documentation.
  10. Submit a pull request!

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

aiopurpleair_ptr727-2026.8.0.tar.gz (19.2 kB view details)

Uploaded Source

Built Distribution

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

aiopurpleair_ptr727-2026.8.0-py3-none-any.whl (22.0 kB view details)

Uploaded Python 3

File details

Details for the file aiopurpleair_ptr727-2026.8.0.tar.gz.

File metadata

  • Download URL: aiopurpleair_ptr727-2026.8.0.tar.gz
  • Upload date:
  • Size: 19.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.4.0 CPython/3.12.13 Linux/6.17.0-1010-azure

File hashes

Hashes for aiopurpleair_ptr727-2026.8.0.tar.gz
Algorithm Hash digest
SHA256 c0d6f476764713d8dc6e684f0cbe1d82e4ff6792d4016b1a3c03394aeca36f62
MD5 ad32565fd588a4b3c4663e7da20dbcb8
BLAKE2b-256 231199ed97590e0a3f191a4aec7ba7518d721632056535fba5b9120a71ae028e

See more details on using hashes here.

File details

Details for the file aiopurpleair_ptr727-2026.8.0-py3-none-any.whl.

File metadata

File hashes

Hashes for aiopurpleair_ptr727-2026.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b0bdca0b143db32fbc44b9e4f7c41dfbe601962a002c7fac8161215281756819
MD5 08cd38b361500cda3f431d82efb8b64d
BLAKE2b-256 527a4f4f65678793b5c826fd6f49ef02b10810f0045a89391e5a4ed368d2e84d

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