🚀 Feature Release

Locations can now be added using the API. This new endpoint requires the access scope write:device.

The lat and lng variables are required on this endpoint to determine whether the radio frequency of the location is supported by Airthings.

Metadata fields such as buildingType, ventilationType, floors, etc. are optional. However, providing metadata information about the location will result in more accurate insights. Note that measurement system used by this endpoint is METRIC.

To add a location, use POST /locations?organizationId={organizationId} with the following example request body:

{
  "name": "My location",
  "lat": 59.918899,
  "lng": 10.7296083,
  "address": "Wergelandsveien 7, 0167 Oslo",
  "buildingType": "OFFICE",
  "ventilationType": "BALANCED",
  "floors": 11,
  "timezone": "Europe/Oslo",
  "buildingYear": 1950,
  "buildingHeight": 35.74,
  "buildingSize": 10000,
  "buildingVolume": 22333.8,
  "usageHours": {
    "monday": {
      "from": "07:00",
      "to": "17:00",
      "closed": false
    },
    "tuesday": {
      "from": "07:00",
      "to": "17:00",
      "closed": false
    },
    "wednesday": {
      "from": "07:30",
      "to": "17:00",
      "closed": false
    },
    "thursday": {
      "from": "07:00",
      "to": "17:00",
      "closed": false
    },
    "friday": {
      "from": "09:00",
      "to": "16:00",
      "closed": false
    },
    "saturday": {
      "closed": true
    },
    "sunday": {
      "closed": true
    }
  }
}

✨ Improvements

Added missing required text on organizationId in some webhooks endpoints

🚀 Feature Release

Webhooks can now be created and retrieved using the API.

To create a webhook, use POST /webhooks?organizationId={{organization_id}} with the following example request body:

{
    "name": "My webhook",
    "url": "https://myurl.com",
    "labels": {"key": "value"},
    "headers": { "key": "value" },
    "measurementSystem": "METRIC/US",
    "devices": ["293000000"],
    "locations": ["0aaac9e8-c26b-4141-9177-1105b65736ae"],
    "active": true
}
{
    "name": "My webhook",
    "url": "https://myurl.com",
    "labels": { "key": "value" },
    "headers": { "key": "value" },
    "measurementSystem": "METRIC/US",
    "locations": [
        {
          "id": "591df93d-ec4e-4780-959c-e8c474e29d7a",
          "name": "Oslo",
          "labels": {}
        }
     ],
    "devices": [
       {
          "id": "293000000",
          "deviceType": "WAVE_PLUS",
          "sensors": ["temp"],
          "segment": {
             "id": "017dd064-0ccd-4902-825e-32e7960edd73",
             "name": "Device name",
             "started": "2021-06-03T15:18:56",
             "active": true
          }
       }
    ],
    "active": true,
    "eventTypes": [
       "hub-meta-data-feed",
       "mold-sample-feed",
       "sample-feed",
       "virus-risk-sample-feed"
    ]
}

Note that except name and url, all other parameters in the request body are optional.
See Webhooks for more information.

Use GET /webhooks?organizationId={{organization_id}} to fetch your list of webhooks.

🚀 Feature Release

"Add device" endpoint is now available. This allows you to automate the process by calling the API instead of adding the devices manually in the dashboard.

This new endpoint requires the new access scope write:device. To use this, make sure your API client is configured with this scope in the dashboard, and use the scope accordingly in the token endpoint as described in the API documentation.

Use POST /location/{locationId}/devices?organizationId={{organization_id}} with the body:

{
    "serialNumber": "2930012345",
    "id": "QWERTYU",
    "name": "Office"
}

Note that while we are using the id property here as the id on the back of the device, id is not always used to describe this. For instance, on the GET endpoints the id might be used as the serial number.

✨ Improvements

The open-api spec (latest-samples and samples endpoints) has been updated removing a map which was incorrectly documented as containing doubles only. It now describes each sensor of the device with type (number/string)

Note: Sensors not existing on a device are not returned in the response. The example below illustrates all possible sensors (the result will vary depending on the sensors available in the device type):

{
  "data": {
    "battery": 0,
    "co2": 0,
    "humidity": 0,
    "light": 0,
    "mold": 0,
    "pm1": 0,
    "pm10": 0,
    "pm25": 0,
    "pressure": 0,
    "radonShortTermAvg": 0,
    "rssi": 0,
    "sla": 0,
    "temp": 0,
    "time": 0,
    "virusRisk": 0,
    "voc": 0,
    "relayDeviceType": "string"
  }
}
{
  "data": {
    "co2": [
      0
    ],
    "humidity": [
      0
    ],
    "light": [
      0
    ],
    "mold": [
      0
    ],
    "pm1": [
      0
    ],
    "pm10": [
      0
    ],
    "pm25": [
      0
    ],
    "pressure": [
      0
    ],
    "radonShortTermAvg": [
      0
    ],
    "sla": [
      0
    ],
    "temp": [
      0
    ],
    "time": [
      0
    ],
    "virusRisk": [
      0
    ],
    "voc": [
      0
    ]
  },
  "start": "2021-04-06T09:28:31.801Z",
  "end": "2021-04-06T09:28:31.801Z",
  "measurementSystem": "US",
  "cursor": "string"
}

✨ Improvements

We have received some feedback about unpaired/retired devices being returned by our endpoints.

Having old devices in the response makes it harder to know if a device in the response is active in an account or not.

To address this we added a new default to hide segments and devices due to unpaired or decommissioned devices from the following endpoints:

/devices
/segments
/locations/{locationId}

Getting old segments of unpaired devices and unpaired devices can still be done by providing the query parameter: showInactive=true

Consider the following response from the /devices endpoint, the device 2930002398 has been decommissioned,
hence its segment is active=false, it is only returned by the endpoint, when the query parameter showInactive=true is present.

{
  "devices": [
    {
      "id": "2930000351",
      "deviceType": "WAVE_PLUS",
      "sensors": [
        "radonShortTermAvg",
        "temp",
        "humidity",
        "pressure",
        "co2",
        "voc",
        "light",
        "virusRisk"
      ],
      "segment": {
        "id": "6b761d0e-c1a4-4607-b52b-2ae6e4320e29",
        "name": "Hardware Area",
        "started": "2018-11-19T16:51:51",
        "active": true
      },
      "location": {
        "id": "0a4fa775-1bed-455b-b1b1-b91d40df667b",
        "name": "Airthings HQ - Oslo"
      }
    },
    {
      "id": "2930002398",
      "deviceType": "WAVE_PLUS",
      "sensors": [
        "radonShortTermAvg",
        "temp",
        "humidity",
        "pressure",
        "co2",
        "voc",
        "light",
        "virusRisk"
      ],
      "segment": {
        "id": "d36a7733-bac9-47af-b8af-094da015e41f",
        "name": "NOx - Meeting Room",
        "started": "2018-12-06T14:46:06",
        "active": false
      },
      "location": {
        "id": "0a4fa775-1bed-455b-b1b1-b91d40df667b",
        "name": "Airthings HQ - Oslo"
      }
    }
  ]
}

✨ Improvements

Battery status (percentage), rssi (signal strength) and relay device type have been added the following
endpoints:

/devices/{serialNumber}/latest-samples
/locations/{locationId}/latest-samples

rssi is only visible for devices which are connected to a hub. relayDeviceType will be "hub" when
the device is connected to a hub and "app" when an app is used to sync data from the device.

Example response:

{
  "data": {
    "co2": 491.0,
    "humidity": 16.0,
    "light": 45,
    "pressure": 1027.8,
    "radonShortTermAvg": 39.0,
    "temp": 22.2,
    "time": 1616143854,
    "virusRisk": 7.0,
    "voc": 54.0,
    "rssi": -45,
    "battery": 83,
    "relayDeviceType": "hub"
  }
}

✨ Improvement

All three types of sample events have received a new ratings property in the data object. This property contains ratings for all sensors in a given sample, wherein the rating for a given sensor value is calculated based on our recommended thresholds. For example, if the temperature is below 18 degrees, it is given a POOR rating.

The ratings are GOOD, FAIR and POOR.

An example response:

{
  "ratings": {
    "radonShortTermAvg": "GOOD",
    "temp": "POOR",
    "pressure": "GOOD",
    "humidity": "FAIR",
    "voc": "GOOD"
  }
}

🚀 Feature Release

  • Virus risk feed is now released. Virus risk events are sent using a new type airthings-webhook-cloudevent-virus-risk-feed

  • Hub metadata feed is now released. Hub events are sent using a new type hub-meta-data-feed and can be selected
    with the other devices/locations in the Dashboard.

About once every hour, the Hub sends metadata to the Airthings cloud informing us about its current status. A few example fields are connectionType (ethernet or cellular), lastSeenDevices(devices seen by the hub within the last 15 minutes), and devices, which shows all devices paired to the hub.

An example event:

{
  "id": "cb0bb746-cdb3-42b5-8a96-db88380e5513",
  "type": "airthings-webhook-cloudevent-hub-meta-data-feed",
  "source": "https://dashboard.airthings.com/integrations/webhooks/f278e95b-26e2-4942-8374-175611b98c36",
  "dataContentType": "application/json",
  "labels": {},
  "data": {
    "serialNumber": "2820000001",
    "recorded": "2020-11-13T13:46:08",
    "lastSeenDevices": [
      "2930000001"
    ],
    "devices": {
      "2930000001": {
        "lastSeen": 1598065353,
        "rssi": -57,
        "type": "wavePlus"
      }
    },
    "connectionType": "ethernet"
  },
  "time": "2020-11-13T13:46:10.280000",
  "specVersion": "0.2"
}

✨ Improvement

  • Two new properties have been added to the data object: rssi (signal strength of the device) and batteryPercentage.

🚀 Feature Release

Two endpoints have been added for fetching full history of samples for virus risk values:

  • /devices/{serialNumber}/virus-risk-samples
  • /segments/{segmentId}/virus-risk-samples

This is considered a beta feature, and it might change in the future.

✨ Improvements

  • Virus risk sensor values has been added to /latest-samples for devices and locations.