Virtual AQI Device

Hello! I am new to creating Hubitat drivers, but not new to coding. I wanted to create a driver that would pull openweathermap AQI data via the API and present it in the current states. I read some other similar drivers to try and get started, but I'm having trouble getting it to show any data.

Could anyone provide some pointers to where I am going wrong? I'm trying to attach my code to this post.

Okay I think I got it working, may as well post it for others. I was just doing some dumb stuff.

/*
	OpenWeatherMap-Air Quality
*/
static String version()	{  return '0.0.1'  }
import groovy.transform.Field


metadata {
    definition (name: "OpenWeatherMap-Air Quality", namespace: "bryan", author: "bryan") {
	capability "AirQuality"
    command 'pollData'
	} 
    preferences {
        input 'apiKey', 'text', required: true, title: 'Type OpenWeatherMap.org API Key Here', defaultValue: null
        input name: "logEnable", type: "bool", title: "Enable debug logging", defaultValue: true
        input name: "txtEnable", type: "bool", title: "Enable descriptionText logging", defaultValue: true
    }
}

void pollAQI() {
	if( apiKey == null ) {
		return
	}
	Map ParamsAQI
	ParamsAQI = [ 
        uri: 'https://api.openweathermap.org/data/2.5/air_pollution?lat=' + (String)location.latitude + '&lon=' + (String)location.longitude + '&appid=' + (String)apiKey, 
        timeout: 20 ]
    if (logEnable) log.debug "ParamsAQI:${ParamsAQI}"
	asynchttpGet('pollAQIHandler', ParamsAQI)
}

void pollAQIHandler(resp, data) {
	if(resp.getStatus() == 200 || resp.getStatus() == 207) {
		Map aqi = parseJson(resp.data)
		if(aqi.toString()==sNULL) {
			pauseExecution(1000)
			pollAQI()
			return
		}
		def name = 'airQualityIndex'
		def value = aqi.list[0].main.aqi
		def descriptionText = "${device.displayName} ${name} is ${value}"
		if (txtEnable) log.info "${descriptionText}"
		sendEvent(name: name,value: value,descriptionText: descriptionText,unit: unit)
	}
}

void refresh() {
}

void installed() {
    schedule("0 0 0/1 1/1 * ? * ", pollAQI)
}

void uninstalled() {
    unschedule()
}

void pollData() {
	pollAQI()
}
2 Likes

Thanks! Got it working and now I can get my air purifiers to turn on automatically when the pollution is high (we're near the wildfires in California). Only surprise was that OpenWeathermap uses a different scale for pollution than I was expecting. At first I thought your device wasn't working, then I read up on the scale: Air Pollution - OpenWeatherMap

Hi, I would love to use this! Is the driver available?

It's in the post linked below, which is also two posts above your post.

  1. Save it as a driver.
  2. Get an OpenWeatherMap API key
  3. Create a virtual device using this driver
1 Like

Awesome! Thank you!

1 Like

I took some liberties here, but I added pulls for specifics. I also set it to pull every 30 minutes.

Thank you Byrin for the original source.

/*
	OpenWeatherMap-Air Quality - Detailed
    Modified from Byrin's original
*/
static String version()	{  return '0.0.2'  }
import groovy.transform.Field


metadata {
    definition (name: "OpenWeatherMap-Air Quality", namespace: "AC7SSM", author: "SJ") {
	capability "AirQuality"
    attribute "CO", "float"
    attribute "NO", "float"
    attribute "NO2", "float"
    attribute "O3", "float"
    attribute "SO2", "float"
    attribute "PM2.5", "float"
    attribute "PM10", "float"
    attribute "NH3", "float"

    command 'pollData'
	} 
    preferences {
        input 'apiKey', 'text', required: true, title: 'Type OpenWeatherMap.org API Key Here', defaultValue: null
        input name: "logEnable", type: "bool", title: "Enable debug logging", defaultValue: true
        input name: "txtEnable", type: "bool", title: "Enable descriptionText logging", defaultValue: true
    }
}

void pollAQI() {
	if( apiKey == null ) {
		return
	}
	Map ParamsAQI
	ParamsAQI = [ 
        uri: 'https://api.openweathermap.org/data/2.5/air_pollution?lat=' + (String)location.latitude + '&lon=' + (String)location.longitude + '&appid=' + (String)apiKey, 
        timeout: 20 ]
    if (logEnable) log.debug "ParamsAQI:${ParamsAQI}"
	asynchttpGet('pollAQIHandler', ParamsAQI)
}

void pollAQIHandler(resp, data) {
	if(resp.getStatus() == 200 || resp.getStatus() == 207) {
		Map aqi = parseJson(resp.data)
		if(aqi.toString()==sNULL) {
			pauseExecution(30000) //5 minute pause
			pollAQI()
			return
		}
		def name = 'airQualityIndex'
		def value = aqi.list[0].main.aqi
		def descriptionText = "${device.displayName} ${name} is ${value}"
		if (txtEnable) log.info "${descriptionText}"
		sendEvent(name: name,value: value,descriptionText: descriptionText,unit: unit)
        // Here begins my modification (SJ)
        name = 'CO'
		value = aqi.list[0].components.co
		descriptionText = "${device.displayName} ${name} is ${value}"
		if (txtEnable) log.info "${descriptionText}"
		sendEvent(name: name,value: value,descriptionText: descriptionText,unit: unit)
       
        name = 'NO'
		value = aqi.list[0].components.no
		descriptionText = "${device.displayName} ${name} is ${value}"
		if (txtEnable) log.info "${descriptionText}"
		sendEvent(name: name,value: value,descriptionText: descriptionText,unit: unit)
        
        name = 'NO2'
		value = aqi.list[0].components.no2
		descriptionText = "${device.displayName} ${name} is ${value}"
		if (txtEnable) log.info "${descriptionText}"
		sendEvent(name: name,value: value,descriptionText: descriptionText,unit: unit)
        
        name = 'O3'
		value = aqi.list[0].components.o3
		descriptionText = "${device.displayName} ${name} is ${value}"
		if (txtEnable) log.info "${descriptionText}"
		sendEvent(name: name,value: value,descriptionText: descriptionText,unit: unit)
        
        name = 'SO2'
		value = aqi.list[0].components.so2
		descriptionText = "${device.displayName} ${name} is ${value}"
		if (txtEnable) log.info "${descriptionText}"
		sendEvent(name: name,value: value,descriptionText: descriptionText,unit: unit)
        
        name = 'PM2.5'
		value = aqi.list[0].components.pm2_5
		descriptionText = "${device.displayName} ${name} is ${value}"
		if (txtEnable) log.info "${descriptionText}"
		sendEvent(name: name,value: value,descriptionText: descriptionText,unit: unit)
        
        name = 'PM10'
		value = aqi.list[0].components.pm10
		descriptionText = "${device.displayName} ${name} is ${value}"
		if (txtEnable) log.info "${descriptionText}"
		sendEvent(name: name,value: value,descriptionText: descriptionText,unit: unit)
        
        name = 'NH3'
		value = aqi.list[0].components.nh3
		descriptionText = "${device.displayName} ${name} is ${value}"
		if (txtEnable) log.info "${descriptionText}"
		sendEvent(name: name,value: value,descriptionText: descriptionText,unit: unit)

	}
}

void refresh() {
}

void installed() {
    schedule("0 0/30 * 1/1 * ? *", pollAQI) //every half hour
}

void uninstalled() {
    unschedule()
}

void pollData() {
	pollAQI()
}

I did not work out an actual AQI number yet. It's a bit complicated to do this evening. But it was fun to give a whirl at coding for once in a long while.

You should add "sensor" as a capability so that the device will be picked up in other apps like HousePanel -- and I think other dashboards will need it too unless they support AirQuality specifically. Just add the line:

capability "Sensor"

1 Like

I will do that in my source, someone already modified their copy with it

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.