Skip to content

Recent measurements

POST {baseUrl}/v2/recent-datasource-measurements-query

By Device

This query is only by Datasource ID. To query by device or reference site, use the historical measurements report.

Returns a list of measurements in time descending order.

Example
url: https://clarity-data-api.clarity.io/v2/recent-datasource-measurements-query
body:

{
    org: "myorg1234",
    datasourceIds: ["DS123456", "DS987654"],
    outputFrequency: "hour",
}

Headers

parameter description
x-api-key string The API key string.
Accept-Encoding string Encoding options, gzip is supported to compress data.

Note: We strongly recommend including it in the headers to reduce response payload size.

Example: Accept-Encoding: gzip

Request

You must include org on all requests. Provide a list of datasources in datasourceIds, or for all the organization's datasources, pass "allDatasources": true.

body parameter description
org string
required
Find the org ID by clicking on your user icon in Dashboard.
Example org ID: "myorgVD43"
allDatasources bool true to retrieve measurements for all datasources in the specified organization for which you have access.
false or omit the parameter if you want to retrict using datasourceIds.
datasourceIds array of string A list of modern datasource ids as returned from /v2/datasources.
Only measurements from periods when the datasource was subscribed by the requested org are returned.

And then add these parameters

additional query parameter description
outputFrequency string The output frequency of the aggregations to return in the measurement. One of:
"minute" default - returns individual measurements, with no aggregation applied.
"hour" returns 1-Hour Mean, 24-Hour Rolling Mean and NowCast aggregations, and AQIs which are calculated on these aggregations as per their standard.
"day" returns 24-Hour Mean aggregations, and AQIs which are calculated on these aggregations as per their standard.
format string The format of the response. One of:
json-long default - A JSON object per metric in a measurement
csv-wide CSV, one row per measurement
startTime string Cut-off time for the earliest measurement desired. If not specified, the start time used will be chosen based on the requested output frequency
minute → 1 hour prior to time of request
hour → 24 hours prior to time of request
day → 48 hours prior to time of request

Measurements are returned from a cache of recent measurements that is limited to the last 48 hours. Earlier times are accepted in the parameter, but only data from the cache will be returned.

Example: startTime: "2023-09-01T00:00:00Z"

Response Formats

json-long

A typical JSON structure including these important objects

  • request - an echo back of the original request
  • data - a list of metrics objects
  • locations - a sidebar dictionary to lookup the location of a datasource

This example is an excerpt of a much longer response:

    "request": {
        "format": "json-long",
        "org": "myorg1234",
        "outputFrequency": "hour",
        "allDatasources": true,
        "startTime": "2023-11-03T19:00:00+00:00"
    },

    "data": [
        {
            "time": "2023-11-03T19:00:00.000Z",
            "status": "sensor-ready",
            "value": 20.25,
            "raw": 20.25,
            "metric": "temperatureInternal1HourMean",
            "datasourceId": "DCQYT1459"
        },
        {
            "time": "2023-11-03T19:00:00.000Z",
            "status": "calibrated-ready",
            "value": 30.41,
            "raw": 30.89,
            "metric": "pm2_5ConcMass1HourMean",
            "datasourceId": "DCQYT1459"
        },
        ...more...
    ],

    "locations": [
        {
            "datasourceId": "DCQYT1459",
            "lon": -122.30173,
            "lat": 37.87864
        },
        {
            "datasourceId": "DDDYN3547",
            "lon": -116.7845,
            "lat": 38.28068
        },
        ...more...
    ]

Note: Best practice is that if a device in a datasource is replaced, the new device should be configured to the same location as the old device. If that does not happen, then it is possible for location to change in the middle of a time-series. If that should occur, then the locations object above will show both locations and identify the first measurement in the time-series that has the new location:

        {
            "datasourceId": "DABCD1234",
            "lon": -120.24056,
            "lat": 37.87864
        },
        {
            "datasourceId": "DABCD1234",               <--- same datasource
            "lon": -122.00052,                         <--- new location
            "lat": 38.28068,
            "startingAt": "2023-11-03T21:00:00.000Z"   <--- first measurement at new location
        },

csv-wide

Column Headers

Automation that processes this response should not assume specifc columns or column ordering. Interpret based on the header row of the response.

The response is like a CSV file: A comma-separated string with an initial header row identifying the columns and with newlines separating the measurements. The set of columns returned depends on the outputFrequency requested.

Identifying columns for all output frequencies:

column header description
datasourceId Unique identifier of the datasource. (string)
sourceId Unique identifier of the underlying device or reference site. (string)
sourceType Either CLARITY_NODE or REFERENCE_SITE. (string)
outputFrequency The output frequency; one of minute, hour, or day. (string)

Example:

datasourceId,sourceId,sourceType,periodType,startOfPeriod,endOfPeriod,locationLatitude,locationLongitude,atmPressureRaw1HourMean,no2ConcCalibrated1HourMean,no2ConcCalibrated1HourMeanUsEpaAqi,no2ConcCalibratedWaDwerAqi,no2ConcRaw1HourMean,no2ConcRaw1HourMeanUsEpaAqi,no2ConcRawWaDwerAqi,o3ConcRaw1HourMean,o3ConcRawWaDwerAqi,pm10ConcMassCalibrated1HourMean,pm10ConcMassCalibrated24HourRollingMean,pm10ConcMassCalibratedWaDwerAqi,pm10ConcMassRaw1HourMean,pm10ConcMassRaw24HourRollingMean,pm10ConcMassRawWaDwerAqi,pm10ConcNumRaw1HourMean,pm10ConcNumRaw24HourRollingMean,pm1ConcMassCalibrated1HourMean,pm1ConcMassRaw1HourMean,pm1ConcNumRaw1HourMean,pm2_5ConcMassCalibrated1HourMean,pm2_5ConcMassCalibrated24HourRollingMean,pm2_5ConcMassCalibratedNowCast,pm2_5ConcMassCalibratedNowCastAqi,pm2_5ConcMassCalibratedWaDwerAqi,pm2_5ConcMassRaw1HourMean,pm2_5ConcMassRaw24HourRollingMean,pm2_5ConcMassRawNowCast,pm2_5ConcMassRawNowCastAqi,pm2_5ConcMassRawWaDwerAqi,pm2_5ConcNumRaw1HourMean,pm2_5ConcNumRaw24HourRollingMean,relHumidAmbientRaw1HourMean,relHumidInternalRaw1HourMean,temperatureAmbientRaw1HourMean,temperatureInternalRaw1HourMean,windDirectionRaw1HourMean,windSpeedRaw1HourMean
DCQYT1459,AXGCR7WJ,CLARITY_NODE,hour,2023-09-01T17:00:00Z,2023-09-01T18:00:00Z,37.878635,-122.301728,,,,,,,,,,,,,0.71,12.45,1,0.91,13.27,,0.0,0.85,,,,,,0.0,9.67,0.02,0,0,0.88,13.18,,54.68,,21.33,,
DDWLW0383,SF3FLYVL,CLARITY_NODE,hour,2023-09-01T17:00:00Z,2023-09-01T18:00:00Z,19.746,-155.087,,,,,9.23,9,9,,,,,,7.27,7.27,7,8.76,8.76,,4.69,8.38,,,,,,7.08,7.08,7.08,30,7,8.72,8.72,,45.12,,21.81,,
DEFSL2364,RW1075XQ,REFERENCE_SITE,hour,2023-09-01T17:00:00Z,2023-09-01T18:00:00Z,45.4369,-75.7261,,,,,,,,31.0,31,,,,,,,,,,,,6.4,,,,6,6.4,,,,6,,,,,,,,
...more...

Example code

Slicing specific columns from CSV

The following sample Python code selects just the columns you want and converts to native Python types.

# simple demo using Clarity Data API

import requests
import os
import csv
import pprint
import datetime


BASEURL = 'https://clarity-data-api.clarity.io'
HEADERS = {
    'Accept-Encoding': 'gzip',
    'x-api-key': os.environ.get('MY_CLARITY_API_KEY') # put your key in the environment or directly here
}


def check_can_connect():
    # verify can reach the API
    response = requests.get(BASEURL, HEADERS)
    http_code = response.status_code
    connected = (http_code == 200)
    if connected:
        print('Connected to Clarity')
    else:
        print(f'{http_code}  :(  Cannot connect')


def get_recent_measurements(org, datasourceIds, outputFrequency):
    # Fetch measurements from the API
    url = BASEURL + '/v2/recent-datasource-measurements-query'
    request_body = {
        'org': org,
        'datasourceIds': datasourceIds,
        'outputFrequency': outputFrequency
    }
    response = requests.post(url, headers=HEADERS, json=request_body)
    response.raise_for_status()
    return response.text


def csv_to_typed(csv_data, fields_to_extract):
    # slice specific columns out of the CSV-style response
    # convert each to best Python type
    # return dictionary

    def convert_to_best_type(value):
        # Try these types in order: float, datetime, else string
        try:
            return float(value)
        except Exception:
            try:
                return datetime.datetime.strptime(value, '%Y-%m-%dT%H:%M:%SZ')
            except Exception:
                return value

    reader = csv.DictReader(csv_data.splitlines())
    return [{field: convert_to_best_type(row[field]) for field in fields_to_extract} for row in reader]


check_can_connect()

tabular = get_recent_measurements(
        org='myorgVD43',
        datasourceIds=['DEXAM0123'],
        format='csv-wide',
        outputFrequency='hour'
    )

measurements = csv_to_typed(tabular, [
    'datasourceId',
    'sourceId',
    'startOfPeriod',
    'pm2_5ConcMass1HourMean'
    ])

pprint.pprint(measurements)