Measuring Air Quality with aqicn.org

Hello there!
In the last couple of days in Poland we’ve seen a drastic increase of AQI.
This is why I thought I will share my openHAB2 setup of air quality measurement :slight_smile:


Just a quick update - you no longer need all of it - you can use the AirQuality binding :slight_smile:

Prerequisites

We will utilize an API of aqicn.org so first thing you need to do is

Setting up your openHAB

  1. Create 3 items (see airquality.items file)
  • Number AirQualityIndex "AQI" - store AQI value
  • String AirQuality - This will display human-friendly SCALE transformation output
  • Switch AirQualityRerun - simple switch for fetching new data
  1. Create a airquality.rules file containing a simple rule for retrieving data from API and sending them accordingly to your items.
    Remember to change your geo coordinates and API token:
    var String coordinates = "37.14360;-115.482399"
    var String token = "YOURTOKEN"
  1. Add some nice SCALE Transformation (here’s Polish version as well)

And you’re done! :slight_smile:

The API has much more details inside, that you can measure as well (like CO, PM2.5 levels etc).

Here’s example response from the API:

{
  "status": "ok",
  "data": {
    "idx": 3402,
    "aqi": 190,
    "time": {
      "v": 1483988400,
      "s": "2017-01-09 19:00:00",
      "tz": "+01:00"
    },
    "city": {
      "name": "Aleja Krasi\u0144skiego, Krak\u00f3w, Ma\u0142opolska",
      "url": "http:\/\/aqicn.org\/city\/poland\/malopolska\/krakow\/aleja-krasinskiego\/",
      "geo": ["50.057678", "19.926189"]
    },
    "attributions": [{
      "name": "Regional Inspectorate for Environmental Protection in Krakow (WIO\u015a - Wojew\u00f3dzki Inspektorat Ochrony \u015arodowiska w Krakowie)",
      "url": "http:\/\/monitoring.krakow.pios.gov.pl\/"
    }, {
      "name": "World Air Quality Index Project",
      "url": "http:\/\/waqi.info\/"
    }],
    "iaqi": {
      "pm25": {
        "v": 190
      },
      "pm10": {
        "v": 137
      },
      "no2": {
        "v": 45
      },
      "co": {
        "v": 19
      },
      "t": {
        "v": -9
      },
      "p": {
        "v": 1024
      },
      "h": {
        "v": 72
      }
    }
  }
}
3 Likes

Quick question - would you be interested in having a dedicated openHAB2 binding for measuring Air Quality Index?

There would be one Thing containing mulitple channels, like aqi, pm25,, pm10 and so on.
I was thinking about it and am willing to do it if there’s enough interest :slight_smile:

Cheers,
Kuba

2 Likes

Yes, Kuba :wink:

Hey @kubawolanin,
I didn’t know about “AQI” but I really like it. Will add it to my system later this week :thumbsup:

A binding would be great! Looking forward to it!

Just a quick update - you no longer need all of it - you can use the AirQuality binding :slight_smile:

2 Likes

Created a custom HabPanel widget if anyone is interested (color coding matches AQI website):

<div ng-if="itemValue('Aqi_Level')<50">
 	<div class="template-container" style="top:0;bottom:0;left:0;right:0;position:absolute;background-color:#009966">
  		<div class="template-contents">
        <div class="row"><span style="color: white">{{itemValue('Aqi_Description')}}</span></div>
    		<div class="row">
      		<div class="col-xs-12"><span style="color: white; font-size: 20pt">{{itemValue('Aqi_Level')}}</span></div>
    		</div>
     		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: white">PM<sub>25</sub>:</span></div>
          <div class="col-xs-6" align="left"><span style="color: white">{{itemValue('Aqi_Pm25')}}</span></div> 
    		</div>
     		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: white">O<sub>3</sub>:</span></div>
      		<div class="col-xs-6" align="left"><span style="color: white">{{itemValue('Aqi_O3')}}</span></div>    
    		</div>
     		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: white">NO<sub>2</sub>:</span></div>
          <div class="col-xs-6" align="left"><span style="color: white">{{itemValue('Aqi_No2')}}</span></div> 
    		</div>
    		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: white">CO:</span></div>
          <div class="col-xs-6" align="left"><span style="color: white">{{itemValue('Aqi_Co')}}</span></div> 
    		</div>
  		</div>
  </div>
</div>

<div ng-if="itemValue('Aqi_Level')>=50 && itemValue('Aqi_Level')<100">
 	<div class="template-container" style="top:0;bottom:0;left:0;right:0;position:absolute;background-color:#ffde33">
  		<div class="template-contents">
        <div class="row"><span style="color: black">{{itemValue('Aqi_Description')}}</span></div>
    		<div class="row">
      		<div class="col-xs-12"><span style="color: black; font-size: 20pt">{{itemValue('Aqi_Level')}}</span></div> 
    		</div>
    		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: black">PM<sub>25</sub>:</span></div>
          <div class="col-xs-6" align="left"><span style="color: black">{{itemValue('Aqi_Pm25')}}</span></div> 
    		</div>
     		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: black">O<sub>3</sub>:</span></div>
      		<div class="col-xs-6" align="left"><span style="color: black">{{itemValue('Aqi_O3')}}</span></div>    
    		</div>
     		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: black">NO<sub>2</sub>:</span></div>
          <div class="col-xs-6" align="left"><span style="color: black">{{itemValue('Aqi_No2')}}</span></div> 
    		</div>
    		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: black">CO:</span></div>
          <div class="col-xs-6" align="left"><span style="color: black">{{itemValue('Aqi_Co')}}</span></div> 
    		</div>
  		</div>
  </div>
</div>

<div ng-if="itemValue('Aqi_Level')>=100 && itemValue('Aqi_Level')<150">
 	<div class="template-container" style="top:0;bottom:0;left:0;right:0;position:absolute;background-color:#ff9933">
  		<div class="template-contents">
        <div class="row"><span style="color: black">{{itemValue('Aqi_Description')}}</span></div>
    		<div class="row">
      		<div class="col-xs-12"><span style="color: black; font-size: 20pt">{{itemValue('Aqi_Level')}}</span></div>
    		</div>
    		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: black">PM<sub>25</sub>:</span></div>
          <div class="col-xs-6" align="left"><span style="color: black">{{itemValue('Aqi_Pm25')}}</span></div> 
    		</div>
     		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: black">O<sub>3</sub>:</span></div>
      		<div class="col-xs-6" align="left"><span style="color: black">{{itemValue('Aqi_O3')}}</span></div>    
    		</div>
     		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: black">NO<sub>2</sub>:</span></div>
          <div class="col-xs-6" align="left"><span style="color: black">{{itemValue('Aqi_No2')}}</span></div> 
    		</div>
    		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: black">CO:</span></div>
          <div class="col-xs-6" align="left"><span style="color: black">{{itemValue('Aqi_Co')}}</span></div> 
    		</div>
  		</div>
  </div>
</div>

<div ng-if="itemValue('Aqi_Level')>=150 && itemValue('Aqi_Level')<200">
 	<div class="template-container" style="top:0;bottom:0;left:0;right:0;position:absolute;background-color:#cc0033">
  		<div class="template-contents">
        <div class="row"><span style="color: white">{{itemValue('Aqi_Description')}}</span></div>
    		<div class="row">
      		<div class="col-xs-12"><span style="color: white; font-size: 20pt">{{itemValue('Aqi_Level')}}</span></div>
    		</div>
     		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: white">PM<sub>25</sub>:</span></div>
          <div class="col-xs-6" align="left"><span style="color: white">{{itemValue('Aqi_Pm25')}}</span></div> 
    		</div>
     		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: white">O<sub>3</sub>:</span></div>
      		<div class="col-xs-6" align="left"><span style="color: white">{{itemValue('Aqi_O3')}}</span></div>    
    		</div>
     		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: white">NO<sub>2</sub>:</span></div>
          <div class="col-xs-6" align="left"><span style="color: white">{{itemValue('Aqi_No2')}}</span></div> 
    		</div>
    		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: white">CO:</span></div>
          <div class="col-xs-6" align="left"><span style="color: white">{{itemValue('Aqi_Co')}}</span></div> 
    		</div>
  		</div>
  </div>
</div>

<div ng-if="itemValue('Aqi_Level')>=200 && itemValue('Aqi_Level')<300">
 	<div class="template-container" style="top:0;bottom:0;left:0;right:0;position:absolute;background-color:#660099">
  		<div class="template-contents">
        <div class="row"><span style="color: white">{{itemValue('Aqi_Description')}}</span></div>
    		<div class="row">
      		<div class="col-xs-12"><span style="color: white; font-size: 20pt">{{itemValue('Aqi_Level')}}</span></div>
    		</div>
     		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: white">PM<sub>25</sub>:</span></div>
          <div class="col-xs-6" align="left"><span style="color: white">{{itemValue('Aqi_Pm25')}}</span></div> 
    		</div>
     		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: white">O<sub>3</sub>:</span></div>
      		<div class="col-xs-6" align="left"><span style="color: white">{{itemValue('Aqi_O3')}}</span></div>    
    		</div>
     		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: white">NO<sub>2</sub>:</span></div>
          <div class="col-xs-6" align="left"><span style="color: white">{{itemValue('Aqi_No2')}}</span></div> 
    		</div>
    		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: white">CO:</span></div>
          <div class="col-xs-6" align="left"><span style="color: white">{{itemValue('Aqi_Co')}}</span></div> 
    		</div>
  		</div>
  </div>
</div>

<div ng-if="itemValue('Aqi_Level')>=300">
 	<div class="template-container" style="top:0;bottom:0;left:0;right:0;position:absolute;background-color:#7e0023">
  		<div class="template-contents">
        <div class="row"><span style="color: white">{{itemValue('Aqi_Description')}}</span></div>
    		<div class="row">
      		<div class="col-xs-12"><span style="color: white; font-size: 20pt">{{itemValue('Aqi_Level')}}</span></div>
    		</div>
     		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: white">PM<sub>25</sub>:</span></div>
          <div class="col-xs-6" align="left"><span style="color: white">{{itemValue('Aqi_Pm25')}}</span></div> 
    		</div>
     		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: white">O<sub>3</sub>:</span></div>
      		<div class="col-xs-6" align="left"><span style="color: white">{{itemValue('Aqi_O3')}}</span></div>    
    		</div>
     		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: white">NO<sub>2</sub>:</span></div>
          <div class="col-xs-6" align="left"><span style="color: white">{{itemValue('Aqi_No2')}}</span></div> 
    		</div>
    		<div class="row">
      		<div class="col-xs-6" align="right"><span style="color: white">CO:</span></div>
          <div class="col-xs-6" align="left"><span style="color: white">{{itemValue('Aqi_Co')}}</span></div> 
    		</div>
  		</div>
  </div>
</div>