clarityio
This package wraps the API for Clarity air quality sensors. It makes calls to v2 of the API, which as of June 2026 is the newest version of the API.
Development status
This package is stable and used in production at the City of Ann Arbor.
Implemented endpoints
- Recent measurements:
POST {baseUrl}/v2/recent-datasource-measurements-query - Recent measurements continuation:
POST {baseUrl}/v2/recent-datasource-measurements-continuation - Historical measurements:
POST {baseUrl}/v2/report-requests - Per-Org Datasources summary:
GET {baseUrl}/v2/datasources - Per-Datasource details:
GET {baseUrl}/v2/datasources/:datasourceId
Not yet implemented
- Devices / nodes:
GET {baseUrl}/v2/devices/nodesand per-node detail/status - Subscriptions:
GET {baseUrl}/v2/subscriptions - Metrics dictionary and other reference endpoints
Installation
Install from PyPI:
pip install clarityio
Usage
Initialize API connection
Find your API key and org in your Clarity.io user profile. Log in at https://dashboard.clarity.io, then click the person icon on the top-right corner.
Use these values to initialize a connection:
import clarityio
import pandas as pd
api_connection = clarityio.ClarityAPIConnection(api_key='YOUR_API_KEY', org='YOUR_ORG')
Both of these values are required to make calls to the Clarity API and are appended as needed by this package.
Retrieve recent measurements
The API limits how far back this endpoint can look (e.g., 48 hours for hourly data). For older data or bounded time windows, use get_historical_measurements() instead.
The default format is json-long, which returns one row per combination of metric and time:
response = api_connection.get_recent_measurements(
all_datasources=True,
output_frequency='hour',
start_time='2024-07-22T00:00:00Z',
)
df = pd.DataFrame(response['data'])
To get wide format (one row per timestamp, each metric in its own column):
from io import StringIO
response_wide = api_connection.get_recent_measurements(
all_datasources=True,
output_frequency='hour',
format='csv-wide',
metric_select='only pm2_5ConcMass24HourRollingMean', # see API docs for metric selection
)
df_wide = pd.read_csv(StringIO(response_wide))
Stream new measurements with a continuation token
To poll for new data without time-based race conditions, seed a continuation token and pass it back on each subsequent call. Each call returns only data that arrived since the previous one. Tokens are valid for 24 hours.
import time
# Seed a token from an initial recent-measurements call
data, token = api_connection.get_recent_measurements(
datasource_ids=['A_DATA_SOURCE_ID'],
reply_with_continuation_token=True,
)
# On each poll, pass the latest token to get only new data
while True:
time.sleep(60)
data, token = api_connection.get_measurements_continuation(token)
if data:
... # process new measurements
Retrieve historical measurements
Use this for arbitrary date ranges or data older than the recent-measurements lookback limits. The method submits an async report, polls until ready, and returns a wide-format DataFrame. Note that the API allows 30 reports per org per day.
df = api_connection.get_historical_measurements(
start_time='2024-01-01T00:00:00Z',
end_time='2024-01-31T00:00:00Z',
all_datasources=True,
output_frequency='hour',
)
The returned DataFrame has one row per datasource/time-period. The timestamp column is startOfPeriod and metric columns follow the pattern {metricName}.value (e.g. pm2_5ConcMass1HourMean.value).
List data sources
datasources_response = api_connection.get_datasources()
datasources = pd.json_normalize(datasources_response['datasources'])
Get details for a specific data source
Obtain the IDs from the prior block of code.
source_details_response = api_connection.get_datasource_details('A_DATA_SOURCE_ID')
source_details = pd.json_normalize(source_details_response['datasource'])
Convert a raw measurement to the EPA AQI scale
The Clarity API provides some of these values, but this utility function offers more flexibility for custom data processing.
clarityio.scale_raw_to_aqi('pm2.5_24hr', 18.84) # 69.14676806083651
clarityio.scale_raw_to_aqi('nitrogen_dioxide_1hr', 300) # 138.64864864864865
Metadata
Release files for clarityio 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| clarityio-1.1.0.tar.gz | 15.2 kB | Without provenance | Details for clarityio-1.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| clarityio-1.1.0-py3-none-any.whl | Python 3 | none | any | Details for clarityio-1.1.0-py3-none-any.whl |
Total release size: 24.6 kB
Release files / clarityio-1.1.0.tar.gz
| Download URL | clarityio-1.1.0.tar.gz |
|---|---|
| Size | 15.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
12b528c7d68b7e94dc07d839c3dc105eccb44ddfaa9e45f899bbac69652fd245
|
|
BLAKE2b-256 checksum How to use checksums |
44a40ffd1d9802552cc4d68c57a8642d702ad0eb0e88b149dccc3be4c516158f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.12
|
Release files / clarityio-1.1.0-py3-none-any.whl
| Download URL | clarityio-1.1.0-py3-none-any.whl |
|---|---|
| Size | 9.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b93da42b234bf7ed2ccf4680fef0354c20c5dc2ed72f87897663e30d06922ce7
|
|
BLAKE2b-256 checksum How to use checksums |
80612674c6a35edb4326794f6bc139ada65ee9ec718d632f02262da751be71d4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.12
|
Security for clarityio 1.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.