i3blocks Air Quality Module
A simple module to keep track of air quality
Hello!
This is post is old and possibly outdated. I’m keeping it here for reference. (2024/09/01)
Overview#
Making API requests then displaying response on i3bar. Using cURL,sed, and AWK to retrieve & manipulate the response data. This post will cover the process of making a module for i3blocks to display the local air quality index (AQI).
Why?#
During my stay in South Korea, I’ve noticed that air quality was a rising isse. The residents are mostly blaming it on the neighbouring country, but I’m not going to get into that.
Rather than fixing the bigger problem, I’ve decided to write a small module for my status bar to keep me updated on the local air quality. I’m doing little things that I can actually achieve.
It’s called a “module” but under the hood, they’re simply a group of commands to display a number on my status bar. Nothing new there. There are existing modules out there to show weather reports, and I knew where to get the AQI from, so all I had to do was simply put the two together.
Preparation#
First I needed to grab the air quality data from somewhere, then I came across this website. By default, it shows your location, local air quality forecast, and explains what the numbers mean.
Further down the page, there’s a link to their API, which returns more information than I needed, so I still needed to put in some effor to make the information usable for the status bar.
I needed to get a token to access the API, which was well documented on the initial setup section of the page. Once I got my token, I was able to make a successful request using cURL:
curl -s http://api.wapi.info/feed/here/?token=yourtoken which returns following format:
{
"status":"ok",
"data":
{
"aqi":69,
"idx":xxxx,
"attributions":
[
{
"url":"https://www.airkorea.or.kr/",
"name":"South Air Korea Environment Corporation"
},
{
"url":"https://waqi.info/",
"name":"World Air Quality Index Project"
}
],
"city":
{
"geo":[latitude,longitude],
"name":"Some City, Some Place, Somewhere, South Korea",
"url":"https://aqicn.org/city/korea/some/place"
},
"time":
{
"s":"2019-07-10 22:00:00",
"tz":"+09:00",
"v":1562796000
},
"debug":
{
"sync":"2019-07-10T22:26:57+09:00"
}
}
} Pretty standard JSON response. Using here returns the local air quality, the website also contains a list of all available cities.
Now What?#
I saved the response to a file, which was done with pipes and redirection.
curl -s http://api.wapi.info/feed/here?token=mytoken > ~/file/location/airdata Now with a file to work with, I had to trim the response because I only needed to AQI value.
I decided to use sed and awk for this text manipulation, there’s a better way to do this probably, but this is how I did it.
sed "s/,/\n/g;s/:/ /g" ~/file/location/airdata | awk /data/ | awk "{print $3}" Breakdown#
sedis a stream editior, it reads the file line by line and performs the operations that are given.s/,/\n/greplaces all the commas with new line character\n.s/:/ /greplaces all the colons with spaces.
awk /data/prints the line that contains the word “data”.awk "{print \$3}"prints the third word of the line.
Output for each command:
{"status" "ok" "data" {"aqi" 69
"data" {"aqi" 69
69 Nice, now that I have what I need, I can move on to the i3blocks part of this.
Some Assembly Required#
Luke Smith’s weather module for LARBS was a good place to start.
I had to modify the script to point to the correct directoy and file, which will be created by the script later.
rm -f "$HOME/.local/share/airdata" ;}
This will clear pre-existing data file when the script runs.
I modified the getforecast() function into get_air_quality().
get_air_quality() {
ping -q -c 1 1.1.1.1 > /dev/null || exit 1
curl -s "http://api.wapi.info/feed/here?token=mytoken" > "$HOME/.local/share/airdata" || exit 1
} This will:
- Check if device is connected to the internet.
- Then send a request to the API.
- Save the response into a file called
airdata.
Which will be read by the script. Then I modified the showforecast() function into show_air_quality().
show_air_quality() {
sed "s/,/\n/g;s/:/ /g" $HOME/.local/share/airdata | awk /data/ | awk "{print "AQI: " $3}"
} This function will return something that looks like AQI: 69, which will be displayed on the status bar.
case $BLOCK_BUTTON in
2) get_air_quality && show_air_quailty ;;
3) pgrep -x dunst >/dev/null && notify-send "Air Quality Module" "- Middle click to update forecast.
-AQI - Air Quality Index
0-50: Good
51-100: Moderate
101-150: Mildly Unhealthy
151-200: Unhealthy" ;;
esac
if [ "$(stat -c %y "$HOME/.local/share/airdata" >/dev/null 2>&1 | awk '{print $1}')" != "$(date '+%Y-%m-%d')" ]
then rm $HOME/.local/share/airdata && get_air_quality && show_air_quality
else show_air_quality
fi Mouse Actions
Each case corresponds to different mouse actions:
1) Left click2) Middle click3) Right clickFor this module, I’ve yet to find a use for left clicking on the module, so I decided to leave it out. I added some descriptions for the numbers. Saved the file as “airquality”, then added it to my i3blocks config gile, then set it to update every 30 minutes.
Final Touches#
Still need to make the script executable. chmod +x ~/.local/bin/statusbar/airquality in my case.
Wrapping Up#
Once I reloaded the i3wm, I was agreeted with an air quality index. The module responds to mouse actions as expected, and I’m happy with the result.
Writing this module was a good practice, since I got to write something that I found useful, and it was pretty easy to do so since most of the work was already done for me. I got to make something I could use everyday.