Integration with Airly

As an author of Air Quality binding this got me interested!
Recently @splatch sent me some info about Airly - a service that aggregates air quality measurements from various sources.
Just like aqicn.org it allows you to create a developer account, so you can consume the data within your service.
An openHAB instance is just ideal way to utilize this data.
When air quality goes bad outside, you can automatically turn on e.g. an air purifier (like the Xiaomi Air Purifier which already works with openHAB thanks to @marcel_verpaalen ) or send a notification to your phone to close the windows if any is open :wink:

A few notes

  • I’m not sure what’s the real range of Airly. Lots of my colleagues is using it in Poland. Make sure it works in your location before you jump in :wink:
  • The difference between Aqicn and this one - if found that the measurements are more accurate here. Plus, they’re updated more frequently, at least here in Kraków.
  • Incorporating Airly in Air Quality binding - I’d love to see some contributions! :slight_smile:

Prerequisites

  • Obtaining an API key -> Go to https://developer.airly.eu/ and sign in. You can use your GitHub account.

  • You need JSONPATH transformation add-on installed

  • You also need HTTP binding (from openHAB 1.x, since there’s no 2.x equivalent for now)

Screenshot

Files

/services/http.cfg

Add the following lines at the bottom. Next:

  • Set your latitude and longitude properly (e.g. latitude=50.12345&longitude=19.12345)
  • (optionally) adjust/decrease the maxDistance parameter so it matches your exact location. Please make sure though that the URL returns valid data, before you paste it into config file.
  • Change the API Key in airly.url parameter to match the key you’ve obtained at Airly API Docs.
  • Set update interval to one hour (3600000 milliseconds).
airly.url="https://airapi.airly.eu/v1/nearestSensor/measurements?latitude=XXXXX&longitude=XXXXX&maxDistance=10000&apikey=YOURAPIKEY"
airly.updateInterval=3600000

/items/airly.items

Group    gAirly     "Airly"
Number   Airly_Aqi  "Airly - Air Quality [%.2f]"     <flow>    (gAirly) {http="<[airly:100000:JSONPATH($.airQualityIndex)]"}
Number   Airly_Pm25 "Pm\u2082\u2085 [%.2f]"          <line>    (gAirly) {http="<[airly:100000:JSONPATH($.pm25)]"}
Number   Airly_Pm10 "Pm\u2081\u2080 [%.2f]"          <line>    (gAirly) {http="<[airly:100000:JSONPATH($.pm10)]"}
DateTime Airly_Time "Measurement time [%1$tH:%1$tM]" <clock>   (gAirly) {http="<[airly:100000:JSONPATH($.measurementTime)]"}

sitemap

sitemap something {
...

            Frame item=gAirly label="Airly" {
                Default item=Airly_Aqi valuecolor=[
                    Airly_Aqi=="-"="lightgray",
                    Airly_Aqi>=300="#7e0023",
                    >=201="#660099",
                    >=151="#cc0033",
                    >=101="#ff9933",
                    >=51="#ffde33",
                    >=0="#009966"
                ]
                Default item=Airly_Pm25
                Default item=Airly_Pm10
                Default item=Airly_Time
            }
...
}

And you’re all set!

Cheers

3 Likes

Unfortunately this works only in Poland :frowning:

@kubawolanin - thank a lot! works like a charm!

1 Like

Hi,

  • After 28.02.2019 the support for API 1.0 will be dropped.
    I still use OHv1 I tried to adapt it using new API v2. Please find my configuration.
    Due to rate limiting on airly.pl website I fetch json file to the local webserver and then re-use it in configuration.

script which download json:

#!/bin/bash

curl -s -X GET \
--header 'Accept: application/json' \
--header 'Accept-Language: pl' \
--header 'apikey: 10f0jTKXzXXXXXXXXXe1woHXr5Q' \
'https://airapi.airly.eu/v2/measurements/installation?installationId=2275' -o /var/www/localserver/airly.json

Next Items:


Group    gAirly     "Airly"
Number   Airly_Aqi  "Air Quality [%.1f]"     <line>    (gAirly) {http="<[http://www.localserver.local/airly.json:100000:JSONPATH($.current.indexes[0].['value'])]"}
Number   Airly_Pm25 "Pm\u2082\u2085 [%.2f]"          <line>    (gAirly) {http="<[http://www.localserver.local/airly.json:100000:JSONPATH($.current.values[1].value)]"}
Number   Airly_Pm10 "Pm\u2081\u2080 [%.2f]"          <line>    (gAirly) {http="<[http://www.localserver.local/airly.json:100000:JSONPATH($.current.values[2].value)]"}
Number   Airly_Pressure "Pressure [%.1f hPa]"          <line>      (gAirly) {http="<[http://www.localserver.local/airly.json:100000:JSONPATH($.current.values[3].value)]"}
Number   Airly_Humidity "Humidity [%.2f %%]"          <line>     (gAirly) {http="<[http://www.localserver.local/airly.json:100000:JSONPATH($.current.values[4].value)]"}
Number   Airly_Temperature "Temperature [%.1f °C]"          <temperature>    (gAirly) {http="<[http://www.localserver.local/airly.json:100000:JSONPATH($.current.values[5].value)]"}
String   Airly_Desc  "Desc: [%s]"     <line>    (gAirly) {http="<[http://www.localserver.local/airly.json:100000:JSONPATH($.current.indexes[0].['description'])]"}
String   Airly_Advice  "Adv: [%s]"     <line>    (gAirly) {http="<[http://www.localserver.local/airly.json:100000:JSONPATH($.current.indexes[0].['advice'])]"}

I had a problem get a number value for Air Quality index. I received value in square brackets. I found that it has to be extracted from json using this syntax: [‘value’]. The same for description and advice which return a string.

(OpenHAB1.x note): If you want to use API URL direclty in Items, you have to sent right headers. Example of binding will be:

 Number   Airly_Pm25 "Pm\u2082\u2085 [%.2f]"          <line>    (gAirly) {http="<[http="<[https://airapi.airly.eu/v2/measurements/point?lat=50.262006&lng=19.980984{Accept:application/json&apikey=yolMiLfyrQXXXXXXXXXXaK8ad782k3}:100000:JSONPATH($.current.values[1].value)]"}

Sitemap:

Frame  label="Airly" {
Text item=Airly_Aqi valuecolor=[Airly_Aqi=="-"="lightgray",Airly_Aqi>=300="#7e0023",>=201="#660099",>=151="#cc0033",>=101="#ff9933",>=51="#ffde33",>=0="#009966"]
//Text item=Airly_Aqi
Text item=Airly_Pm25
Text item=Airly_Pm10
Text item=Airly_Pressure
Text item=Airly_Temperature
Text item=Airly_Humidity
Text item=Airly_Desc
Text item=Airly_Advice
}

result:

image

2 Likes

@Grzegorz - thnx for info. In this API there is much more info than in proximity based (e.g. temperature, humidity, pressure, history of readings).

I am using raspi, and droping json into /etc/openhab2/html directory.
Then reading :8080/static/airly.json
i.e.

sudo curl -s -X GET \
--header 'Accept: application/json' \
--header 'Accept-Language: pl' \
--header 'apikey: PUT_YOUR_API_KEY' \
'https://airapi.airly.eu/v2/measurements/installation?installationId=825' \
-o /etc/openhab2/html/airly2.json

Then adding also percentage values as speaks stronger to me than just PM2.5/PM10 values.

Number   Airly_Pm25Percent "% norm Pm\u2082\u2085 [%.0f%%]"    <line>          (gAirly) {http="<[http://localhost:8080/static/airly.json:100000:JSONPATH($.current.standards[0].percent)]"}
Number   Airly_Pm10Percent "% norm Pm\u2081\u2080 [%.0f%%]"    <line>          (gAirly) {http="<[http://localhost:8080/static/airly.json:100000:JSONPATH($.current.standards[1].percent)]"}

I’ve used JSONPATH as described here:


as more resistant to changes in the index of measurements in the response from the API.
I query 3 installations (URLs) and for each update interval for:

airly_arbuzowa.url="https://airapi.airly.eu/v2/measurements/installation?installationId=2709&apikey=<api_key>"
airly_arbuzowa.updateInterval=600000

so i’m below API limit, as i can see that updating items is done from the cache, e.g.:

2019-03-10 22:07:21.624 [DEBUG] [ab.binding.http.internal.HttpBinding] - item 'Airly_Arbuzowa_Aqi' is fetched from cache
2019-03-10 22:07:21.665 [DEBUG] [ab.binding.http.internal.HttpBinding] - transformed response is '6.23'