Integrate AirGradient with OpenHAB
How I integrated my AirGradient pro kit with OpenHAB
AirGradient
There are a lot of forks of AirGradient’s sample code but none were exactly what I needed to integrate into my OpenHAB setup so I started a clean fork and cherry picked/adjusted to keep it as close to AirGradient’s reference implementation as possible
/compare/master…neutmute:arduino:master
With these changes, I can now browse to my AirGradient device IP and receive the data in JSON
{"wifi":-83, "rco2":486, "pm01":1, "pm10":1, "pm02":2, "pm02_aqi":8, "tvoc_index":100, "nox_index":1, "atmp":20.30, "rhum":76}
OpenHAB
Things
To expose the JSON data, it’s a simple HTTP binding
Thing http:url:airgradient "AirGradient" [
baseURL="http://192.168.20.138/",
contentType="application/json",
refresh=30] {
Channels:
Type number : wifi "WiFi Signal Strength" [ stateTransformation="JSONPATH:$.wifi" ]
Type number : co2 "RCO2" [ stateTransformation="JSONPATH:$.rco2" ]
Type number : pm01 "PM 0.1" [ stateTransformation="JSONPATH:$.pm01" ]
Type number : pm10 "PM 10" [ stateTransformation="JSONPATH:$.pm10" ]
Type number : pm02 "PM 0.2" [ stateTransformation="JSONPATH:$.pm02" ]
Type number : pm02Aqi "PM 0.2 AQI" [ stateTransformation="JSONPATH:$.pm02_aqi" ]
//Type number : tvoc_index "TVOC Index" [ stateTransformation="JSONPATH:$.tvoc_index" ] // I don't have the TVOC module
Type number : nox "NOX" [ stateTransformation="JSONPATH:$.nox_index" ]
Type number : temperature "Temperature" [ stateTransformation="JSONPATH:$.atmp" ]
Type number : humidity "Humidity" [ stateTransformation="JSONPATH:$.rhum" ]
}
Items
Define the items with a bit of help from ChatGPT
Number AirGradientWiFiSignal "WiFi Signal Strength [%.0f dBm]" { channel="http:url:airgradient:wifi" }
Number AirGradientCO2 "CO₂ [%.0f ppm]" { channel="http:url:airgradient:co2" }
Number AirGradientPM01 "PM 0.1 [%.0f µg/m³]" { channel="http:url:airgradient:pm01" }
Number AirGradientPM10 "PM 10 [%.0f µg/m³]" { channel="http:url:airgradient:pm10" }
Number AirGradientPM02 "PM 2.5 [%.0f µg/m³]" { channel="http:url:airgradient:pm02" }
Number AirGradientPM02AQI "PM 2.5 AQI [%.0f]" { channel="http:url:airgradient:pm02Aqi" }
//Number AirGradientTVOCIndex "TVOC Index [%.0f]" { channel="http:url:airgradient:tvoc_index" }
Number AirGradientNox "Nitrous Oxides [%.0f]" { channel="http:url:airgradient:nox" }
Number AirGradientTemperature "Temperature [%.1f °C]" <Temperature> { channel="http:url:airgradient:temperature" }
Number AirGradientHumidity "Humidity [%.0f %%]" <Humidity> { channel="http:url:airgradient:humidity" }
Sitemap
sitemap airgradient label="Air Gradient"
{
Frame label="Air Quality" {
Text item=AirGradientWiFiSignal
Text item=AirGradientCO2
Text item=AirGradientPM01
Text item=AirGradientPM10
Text item=AirGradientPM02
Text item=AirGradientPM02AQI
//Text item=AirGradientTVOCIndex
Text item=AirGradientNox
}
Frame label="Temperature & Humidity" {
Text item=AirGradientTemperature
Text item=AirGradientHumidity
}
}
InfluxDB Persist
With persistence to Influx, the only step remaining is some Grafana charting
AirGradientWiFiSignal: strategy =everyChange, every10Minutes
AirGradientCO2 : strategy =everyChange, every10Minutes
AirGradientPM01: strategy =everyChange, every10Minutes
AirGradientPM10: strategy =everyChange, every10Minutes
AirGradientPM02: strategy =everyChange, every10Minutes
AirGradientPM02AQI : strategy =everyChange, every10Minutes
AirGradientNox : strategy =everyChange, every10Minutes
AirGradientTemperature : strategy =everyChange, every10Minutes
AirGradientHumidity : strategy =everyChange, every10Minutes