Having seen a tweet to a Hackaday article (/ht Andy Piper) about adding a ESP8266 to the new IKEA VINDRIKTNING air quality sensor.

The sensor is a little stand alone platform that measures the amount of PM 2.5 particles in the air and it has an array of coloured LEDs on the front to show a spectrum from green when the count is low and red when high.
Sören Beye opened one up and worked out that the micro controller that reads the sensor to control the leds does so over a uart serial connection and that the Tx/Rx lines were exposed via a a set of test pads along with 5v and Ground power. This makes it easy to attach a second micro controller to the Rx line to read the response when the sensor is polled.
Sören has written some code for an ESP8266 to decode that response and publish the result via MQTT.
Making the hardware modification is pretty simple

- Unscrew the case
- Strip the ends on 3 short pieces of wire
- Solder the 3 leads to the test pads labelled 5v, G and REST
- Solder the 5V to 5V, G to G and REST to D2 (assuming using a Wemos D1 Mini)
- Place the Wemos in the empty space above the sensor
- Screw the case back together
The software is built using the Ardunio IDE and is easily flashed via the USB port. Once installed when the ESP8266 boots it will set up a WiFi Access Point to allow you to enter details for the local WiFi network and the address, username and password for a MQTT broker.
When connected the sensor publishes a couple of messages to allow auto configuration for people who use Home Assistant but it also publishes messages like this:
{
"pm25":12,
"wifi":{
"ssid":"IoT Network",
"ip":"192.168.1.58",
"rssi":-60
}
}
It includes the pm25
value and information about which network it’s connected to and it’s current IP address. I’m subscribing to this with Node-RED and using it to convert the numerical value, which has units of μg/m3 into a recognised scale (found on page 4).
let pm25 = msg.payload.pm25
if ( pm25 < 12 ) {
msg.payload.string = "good"
} else if (pm25 >= 12 && pm25 < 36) {
msg.payload.string = "moderate"
} else if (pm25 >= 36 && pm25 < 56) {
msg.payload.string = "unhealthy for sensitive groups"
} else if (pm25 >= 56 && pm25 < 151 ) {
msg.payload.string = "unhealthy"
} else if (pm25 >= 151 && pm25 < 251 ) {
msg.payload.string = "very unhealthy"
} else if (pm25 >= 251 ) {
msg.payload.string = "hazardous"
}
return msg;
I’m feeding this into a Google Smart Home Assistant Sensor device that has the SensorState trait, this takes the scale values as input, but you can also include the raw values as well.
msg.payload = {
"params":{
"currentSensorStateData":[
{
"name":"AirQuality",
"currentSensorState":msg.payload.string
},
{
"name":"PM2.5",
"rawValue": msg.payload.pm25
}
]
}
}
return msg;
I will add the an Air Quality trait to the Node-RED Google Assistant Bridge shortly.
I’m also routing it to gauge in a Node-RED Dashboard setup.
