Airthings

The Airthings connector brings indoor air quality, occupancy, and environmental telemetry from Airthings devices into the Mapped graph. It uses Airthings locations, segments, and devices to build a place and device model, receives live measurements through persistent webhooks, and can run an on-demand backfill job to import historical samples for the same points.
This connector uses Connector Entities: you import your Airthings locations, segments and devices into review grids, choose what to bring in, and save.
Use Cases
- Indoor air quality monitoring: Track CO₂, humidity, temperature, radon, particulate, TVOC, pressure, light, and sound measurements from Airthings sensors.
- Occupancy insights: Capture occupancy count values from supported devices alongside the spaces and zones they serve.
- Historical analysis: Backfill prior Airthings measurements into the same points used by the live webhook feed for trend analysis and reporting.
How it works
Work through the Locations, Segments and Devices sections in that order. Segments need the buildings and floors they belong to, and devices need the places they sit in. Once devices are saved, live measurements flow in on their own. For older history, run the backfill job.
Configuration
Auth Requirements
The connector authenticates with Airthings using OAuth2 client_credentials.
| Field | Required | Description | Where to Find |
|---|---|---|---|
| Client ID | Yes | Airthings API client ID used to request OAuth access tokens | Your Airthings API application in the Airthings developer portal |
| Client Secret | Yes | Airthings API client secret paired with the Client ID | Your Airthings API application in the Airthings developer portal |
Advanced Options
Set these before you import, because they decide the shape of what gets created.
| Option | Default | Description |
|---|---|---|
| Materialize mapped spaces as Zones | false | When enabled, imported Airthings segments are created as Zone vertices instead of Space vertices. Devices can still be located on them, and the connector still creates an additional child zone per device. See the graph shape when false (Segments become Spaces) and when true (Segments become Zones). |
| Temperature Unit | Celcius | Controls whether temperature points are created in DEG_C or DEG_F, and aligns webhook and backfill temperature ingestion to the same unit. |
Entities
The connector exposes three sections, one per Airthings source type: Locations, Segments and Devices. Each section is its own Entities screen with a Grid and a Rules tab. In each one:
- Click Import to load the current list from Airthings.
- Tick the rows you want, and fill in or edit the cells (the tables below list them).
- Optionally use the Rules tab to fill cells and tick rows automatically. See Merge Rules.
- Click Save, review the changes, and Submit.
See Connector Entities for how the Grid, repeated imports and Save work.
Locations
Locations come from the Airthings Location resource and are materialized as Mapped buildings.
| Field | Required | Source | Description |
|---|---|---|---|
| Name | Yes | Airthings | Building name from the Airthings location |
| Postal Address | Yes | User (pre-filled when available) | Building address used for the Mapped building |
| Site | Yes | User | Existing Mapped site that will own the building |
Segments
Segments come from the Airthings Segment resource and represent rooms or spaces inside a building.
| Field | Required | Source | Description |
|---|---|---|---|
| Name | Yes | Airthings | Segment name |
| Space Code | No | Airthings label / User | Optional room code used to contribute to an existing room in the graph |
| Floor | Yes | User | Existing Mapped floor that will contain the segment |
Note: Airthings does not provide a first-class floor resource, so floors must already exist in the Mapped graph and are selected by the user.
Devices
Devices come from the Airthings Device resource. Hub devices are excluded; sensing devices are imported.
| Field | Required | Source | Description |
|---|---|---|---|
| Name | Yes | Airthings | Device product name |
| exactType | Yes | Connector default | Air_Quality_Sensing_Device |
| Location | Yes | Airthings / User | Target Mapped space or zone for the device. This is pre-filled when the reported Airthings segment already exists in the graph. |
Enumerations
This connector does not require user-defined enumeration mappings.
Actions
Live measurements
Once devices are saved, Airthings sends live measurements to Mapped through persistent webhooks. They are written to the points on each device (see Timeseries Points).
Backfill job
An on-demand backfill job imports historical telemetry into the same points the live feed uses. It has these options:
- Devices: all mapped devices, or only specific serial numbers
- Date Range: the history window to import
- Resolution:
RAW,HOUR,FOUR_HOURS,DAY,THREE_DAYS, orWEEK
Mapped Concepts
The connector creates buildings from locations, creates segment places beneath the floors you select, places air quality sensing devices in those segment places, attaches an additional device zone under each segment place, and writes live or historical measurements to points on each device.
Graph Entities
API to Mapped Entities
| Airthings Source | Mapped Entity | exactType | Relationship |
|---|---|---|---|
| Location | Building | Building | isPartOf → Site |
| Segment | Space (default mode) | Space | isPartOf → Floor |
| Segment | Zone (when Materialize mapped spaces as Zones is enabled) | Zone | isPartOf → Floor |
| Device | Thing | Air_Quality_Sensing_Device | hasLocation → imported segment place |
| Derived per-device zone | Zone | Occupancy_Zone | hasPart from the imported segment place; isServedBy from the device |
Graph Shape: Default Mode
Graph Shape: Segment-as-Zone Mode
Time Series
API to Mapped Points
Points are created on each Airthings device according to the sensor list reported for that device. Live webhook events and backfill history both write into the same device points.
| Airthings Measurement | Mapped Point | Datatype | Unit | Description |
|---|---|---|---|---|
co2 | CO2_Level_Sensor | DOUBLE | PPM | Carbon dioxide concentration |
humidity | Humidity_Sensor | DOUBLE | PERCENT_RH | Relative humidity |
pm1 | PM1_Level_Sensor | DOUBLE | PPB | PM1 concentration |
pressure | Pressure_Sensor | DOUBLE | HectoPA | Air pressure |
occupants | Occupancy_Count_Sensor | DOUBLE | NUM | Occupancy count reported by the device |
pm10 | PM10_Level_Sensor | DOUBLE | PPB | PM10 concentration |
pm25 | PM2.5_Level_Sensor | DOUBLE | PPB | PM2.5 concentration |
light | Illuminance_Sensor | DOUBLE | LUX | Illuminance |
temp | Air_Temperature_Sensor | DOUBLE | DEG_C or DEG_F | Temperature, based on the configured temperature unit |
radonShortTermAvg | Radon_Concentration_Sensor | DOUBLE | BQ-PER-M3 | Short-term average radon concentration |
voc / tvoc | TVOC_Sensor | DOUBLE | PPB | Total volatile organic compounds |
sla / soundLevelA | Sound_Pressure_Level_Sensor | DOUBLE | DeciB | Sound pressure level, when the device exposes this measurement |
Heartbeats
This connector does not currently implement heartbeats.
Sample Code
There are a few likely ways you'd want to retrieve the air quality data - first would be if you knew which sensor in specific you wanted to look up. Temperature points use the unit set in Temperature Unit (Fahrenheit in this example):
{
things(filter: {id: {eq: "THGu8jzPde0IgxLd6GncfBAep"}}) {
id
name
exactType
points {
id
name
unit {
name
}
series(latest: true) {
timestamp
value {
float64Value
}
}
}
}
}
An alternative might be to look up a specific space the sensor is located in:
{
spaces(filter: {id: {eq: "SPC8DwkNhFdnXsiVpzz63FfkC"}}) {
id
name
things {
id
name
points {
id
name
exactType
series(latest: true) {
timestamp
value {
float64Value
}
}
}
}
}
}
Each device is also attached to its own per-device zone (type Occupancy_Zone), so you can look up the same points through that zone:
{
zones (filter: {id: {eq: "ZONEUPgHV7iB3m03nbqnsGpWL"}}) {
id
name
things {
id
name
points {
id
name
exactType
series(latest: true) {
timestamp
value {
float64Value
}
}
}
}
}
}