Airthings Cloud
Read-only telemetry driver for Airthings indoor air-quality sensors — View Plus, View Radon, View Pollution, Wave Plus, Wave Radon, Wave Mini, House Kit. Reports:
- Radon (Bq/m³, short-term average)
- CO₂ (ppm)
- VOC (ppb)
- PM 2.5 (µg/m³)
- PM 1 (µg/m³)
- Temperature (°C)
- Humidity (% RH)
- Atmospheric pressure (mbar)
- Battery (%)
- Last-reported timestamp
Auth is OAuth2 client-credentials — the integrator creates an API integration in the Airthings Dashboard, pastes the resulting client_id and client_secret into GEM, and the driver mints and refreshes bearer tokens automatically.
Airthings hardware is sensor-only. There is no control surface — the driver exposes discovery and refresh commands, but nothing to actuate. Use zone triggers or the Automation Builder to drive HVAC / ventilation actions in response to sensor readings.
Prerequisites
- An Airthings Dashboard account (Consumer or Business tier) with the sensors already registered:
- Consumer devices (Wave Plus / Wave Radon / Wave Mini) are onboarded in the Airthings mobile app; readings appear in the dashboard once the app has synced.
- View-series and Business fleet devices are onboarded through dashboard.airthings.com.
- An API integration created in the Airthings Dashboard under Integrations → API Integrations. The dashboard returns a
client_idandclient_secret; the secret is only shown once at creation time — copy it before closing the dialog. - Outbound HTTPS from the GEM host to
accounts-api.airthings.comandext-api.airthings.com.
Setup
- Sign in at dashboard.airthings.com and create a new API integration. Record the
client_idandclient_secret. - In GEM, navigate to Admin → Devices and click Add Device.
- Choose airthings_cloud as the driver.
- Fill in:
- API Client ID (
client_id) - API Client Secret (
client_secret) — stored encrypted
- API Client ID (
- Leave OAuth Scope on the default
read:device:current_valuesunless you need broader access. - Save. The driver authenticates, fetches the device list, and reports
connected: true. - From the device detail page's Commands tab, run get_devices. The response is one entry per registered sensor — record the
serialNumbervalues (10-digit numeric strings). - Under Admin → Zones, create one zone per sensor:
- Subsystem: pick or create an environmental / air-quality subsystem (a
sensorsubsystem works too). - Address: paste the sensor
serialNumber.
- Subsystem: pick or create an environmental / air-quality subsystem (a
- Wait one
status_interval(default 5 minutes) for the zone's telemetry attributes (radon,co2,voc,temperature,humidity,pm25,pm1,pressure,battery_level,last_reported) to populate — or run get_readings on the device to trigger an immediate refresh.
Attribute reference
Device attributes
| Attribute | Required | Description |
|---|---|---|
client_id | yes | OAuth2 client_id from the Airthings Dashboard. |
client_secret | yes | OAuth2 client_secret from the Airthings Dashboard. Stored encrypted (gem-crypt: envelope). |
scope | no | OAuth scope requested. Default read:device:current_values. |
api_base | no | Data endpoint. Default https://ext-api.airthings.com. |
token_url | no | Token endpoint. Default https://accounts-api.airthings.com/v1/token. |
status_interval | no | Poll interval in ms. Default 300000 (5 minutes), floor 60000. |
request_timeout | no | HTTP request timeout in ms. Default 15000. |
Zone attributes (populated by the driver)
| Attribute | Type | Unit | Description |
|---|---|---|---|
radon | int | Bq/m³ | Short-term average radon. Divide by 37 for pCi/L. |
co2 | int | ppm | Ambient CO₂. |
voc | int | ppb | Total volatile organic compounds. |
pm25 | int | µg/m³ | PM 2.5 particulate mass. |
pm1 | int | µg/m³ | PM 1 particulate mass. |
temperature | float | °C | Ambient temperature to 0.1°. |
humidity | int | % RH | Relative humidity. |
pressure | int | mbar | Atmospheric pressure. |
battery_level | int | % | Battery percentage (battery-powered sensors only). |
last_reported | string | ISO 8601 | Timestamp of the last cloud-reported sample. |
Sensor coverage varies by model — a Wave Mini reports temperature + humidity + VOC only, a View Plus reports the full set. The driver only writes attributes that appear in the sample; missing sensors leave the zone attribute at its previous value (or null if never seen).
Zone address format
zone.address = the Airthings serialNumber — a 10-digit numeric string (e.g. 2960123456).
Run get_devices on the driver device to enumerate; the response includes serialNumber, deviceType, sensor list, location metadata, and segment name for each registered sensor.
Commands
| Command | Args | Notes |
|---|---|---|
get_devices | — | List every sensor registered under the integration. Refreshes the driver's internal deviceIndex. |
get_locations | — | List locations / segments the integration has access to. |
get_readings | address | Fetch the latest sample for one sensor and mirror it onto the mapped zone immediately. |
Known limitations
- Radon updates hourly on the sensor side — the cloud returns the same value between updates. Polling faster than hourly does not surface fresher radon data.
- Battery-powered sensors need a Hub (or the phone app in range) to upload. Without a Hub, gaps of hours or days are normal. For continuous logging use a View-series (Wi-Fi native) sensor or an Airthings Hub.
- No control surface. The API does not expose settings/thresholds/lighting — everything is read-only.
- Rate limits. Default account limit is 120 API requests per hour. The driver polls each zone once per
status_interval; a 5-minute interval with 10 sensors uses exactly the quota. Raisestatus_intervalfor larger fleets. - Timestamp units vary. The API sometimes returns
timeas a Unix epoch seconds integer and sometimes as an ISO string depending on device generation — the driver normalises to ISO 8601 forlast_reported. - Units are SI — °C, mbar, Bq/m³. Convert in your UI/macros for imperial displays (
× 1.8 + 32for °F,÷ 37for pCi/L radon).
Troubleshooting
| Symptom | Likely cause |
|---|---|
airthings cloud auth failed on connect with http 401 on the token endpoint | client_id or client_secret typo, or the integration was deleted in the dashboard. Recreate and paste the new pair. |
get_devices returns an empty list | Integration is scoped to a workspace that owns no devices, or all sensors are inactive. Verify in the Airthings Dashboard's Devices list. |
| Zone attributes stay stale for hours | Battery sensor with no Hub and the app hasn't synced. Add a Hub or switch to a View-series Wi-Fi sensor. |
http 429 errors in the log | Poll rate exceeded the account cap. Raise status_interval, split sensors across multiple integrations, or contact Airthings support to raise the quota. |
last_reported is much older than "now" but the sensor is powered | Wave-series device is waiting for the Airthings Hub / phone app to next relay. Check the mobile app's device screen for the last sync time. |
References
- Airthings for Consumer: airthings.com
- Airthings for Business API docs: developer.airthings.com
- API Integrations dashboard: dashboard.airthings.com