# Ikea Vindriktning Hack with QT Py ESP32-S3 and Adafruit IO

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/122/215/medium800/hacks_edited_P1410098.png?1688148485)

Warning: This project has only been tested with a QT Py ESP32-S3. Other boards may not work as expected.

The [Ikea Vindriktning](https://www.ikea.com/us/en/p/vindriktning-air-quality-sensor-60515911/) is a small and affordable air quality monitor that measures PM2.5 particulates for an AQI reading. The light bar on the front changes from green, yellow or red depending on the reading. It's a fun little device, but it would be great to make it internet of things (IoT) capable and this guide will show you how to do just that.

https://youtube.com/shorts/RsOykiq8foc

You'll add a QT Py ESP32-S3 running CircuitPython to read the data from the [PM1006 sensor](https://cdn-learn.adafruit.com/assets/assets/000/122/217/original/PM1006_LED_PARTICLE_SENSOR_MODULE_SPECIFICATIONS-1.pdf?1688148991) inside the Vindriktning and log the data to Adafruit IO. You'll also set up an Action alert to know when the air quality becomes unhealthy.

![hacks_edited_P1410102.png](https://cdn-learn.adafruit.com/assets/assets/000/122/218/medium640/hacks_edited_P1410102.png?1688150016)

This Ikea hack is non-destructive to the electronics inside the Vindriktning. You'll solder to three already exposed test points. The LEDs on the PCB will continue to light up depending on the value from the PM1006 sensor.

![hacks_edited_P1400862.png](https://cdn-learn.adafruit.com/assets/assets/000/122/197/medium640/hacks_edited_P1400862.png?1688006434)

The QT Py is able to be powered by the USB C port in the Vindriktning through its battery pads on the bottom of the board. The PM1006 sends data over UART, which is read through the **RX** pin on the QT Py.

![hacks_edited_P1410070.png](https://cdn-learn.adafruit.com/assets/assets/000/122/198/medium640/hacks_edited_P1410070.png?1688006504)

## Parts
### Adafruit QT Py ESP32-S3 WiFi Dev Board with STEMMA QT

[Adafruit QT Py ESP32-S3 WiFi Dev Board with STEMMA QT](https://www.adafruit.com/product/5426)
The ESP32-S3 has arrived in QT Py format - and what a great way to get started with this powerful new chip from Espressif! With dual 240 MHz cores, WiFi and BLE support, and native USB, this QT Py is great for powering your IoT projects.

The ESP32-S3&nbsp;is a highly-integrated,...

Out of Stock
[Buy Now](https://www.adafruit.com/product/5426)
[Related Guides to the Product](https://learn.adafruit.com/products/5426/guides)
![Angled shot of small purple microcontroller.](https://cdn-shop.adafruit.com/640x480/5426-00.jpg)

### Silicone Cover Stranded-Core Wire - 30AWG in Various Colors

[Silicone Cover Stranded-Core Wire - 30AWG in Various Colors](https://www.adafruit.com/product/2051)
Silicone-sheathing wire is super-flexible and soft, and its also strong! Able to handle up to 200°C and up to 600V, it will do when PVC covered wire wimps out. We like this wire for being extremely supple and flexible, so it is great for wearables or projects where the wire-harness has to...

Out of Stock
[Buy Now](https://www.adafruit.com/product/2051)
[Related Guides to the Product](https://learn.adafruit.com/products/2051/guides)
![Silicone Cover Stranded-Core Wire - 30AWG in Various Colors laid out beside each other. ](https://cdn-shop.adafruit.com/640x480/2051-01.jpg)

### Pink and Purple Woven USB A to USB C Cable - 2 meters long

[Pink and Purple Woven USB A to USB C Cable - 2 meters long](https://www.adafruit.com/product/5044)
This cable is not only super-fashionable, with a woven pink and purple Blinka-like pattern, it's also made for USB C for our modernized breakout boards, Feathers and more.&nbsp; [If you want something just like it but for Micro B, we have a B...](https://www.adafruit.com/product/4111)

Out of Stock
[Buy Now](https://www.adafruit.com/product/5044)
[Related Guides to the Product](https://learn.adafruit.com/products/5044/guides)
![Angled shot of a pink/purple woven USB cable plugged into a laptop port and a small dev board.](https://cdn-shop.adafruit.com/640x480/5044-04.jpg)

### Part: Ikea Vindriktning Air Quality Sensor
quantity: 1
Air quality sensor
[Ikea Vindriktning Air Quality Sensor](https://www.ikea.com/us/en/p/vindriktning-air-quality-sensor-60515911/)

## Optional - Adafruit IO+

This project can utilize the free tier of Adafruit IO. However, if you would like to set up text alert actions as described later in the guide you will need an IO+ subscription.

### Adafruit IO+ Subscription Pass – One Year

[Adafruit IO+ Subscription Pass – One Year](https://www.adafruit.com/product/3792)
The all-in-one Internet of Things service from Adafruit you know and love is now _even better_ with IO+. The 'plus' stands for MORE STUFF! More feeds, dashboards, storage, speed. Power up your [Adafruit IO](https://io.adafruit.com/) with the $99 pass for 1 year of the...

In Stock
[Buy Now](https://www.adafruit.com/product/3792)
[Related Guides to the Product](https://learn.adafruit.com/products/3792/guides)
![Text image that reads "IO+"](https://cdn-shop.adafruit.com/640x480/3792-01.jpg)

# Ikea Vindriktning Hack with QT Py ESP32-S3 and Adafruit IO

## Circuit Diagram

![](https://cdn-learn.adafruit.com/assets/assets/000/122/150/medium800/hacks_circuitDiagram.png?1687893198)

Connect the QT Py ESP32-S3 to three test points on the air quality monitor PCB.

- **PCB 5V test point** to **QT Py BAT + (red wire)**
- **PCB GND test point** to **QT Py BAT GND (black wire)**
- **PCB REST test point** to **QT Py RX (green wire)**

# Ikea Vindriktning Hack with QT Py ESP32-S3 and Adafruit IO

## Get Started with Adafruit IO

Adafruit IO is integrated with your&nbsp;[adafruit.com account](https://accounts.adafruit.com/)&nbsp;so you don't need to create yet another online account! You need an Adafruit account to use Adafruit IO because we want to make sure the data you upload is available to only you (unless you decide to publish your data).

## I have an Adafruit.com Account already

**If you already have an Adafruit account, then you already have access to Adafruit IO**. It doesn't matter how you signed up, your account will make all three available.

To access Adafruit IO, simply visit [https://io.adafruit.com](https://io.adafruit.com) to start streaming, logging, and interacting with your data.

## Create an Adafruit Account (for Adafruit IO)

An Adafruit account makes Adafruit content and services available to you in one place. Your account provides access to the [Adafruit shop](https://www.adafruit.com/), the [Adafruit Learning System](https://learn.adafruit.com/), and [Adafruit IO](https://io.adafruit.com/). This means only one account, one username, and one password are necessary to engage with the content and services that Adafruit offers.

If you do not have an Adafruit account, signing up for a new Adafruit account only takes a couple of steps.

Begin by visiting [https://accounts.adafruit.com](https://accounts.adafruit.com).

**Click the Sign Up button** under the "Need An Adafruit Account?" title, below the Sign In section.

![](https://cdn-learn.adafruit.com/assets/assets/000/125/220/medium800/adafruit_io_Create_account_sign_in_up_page.png?1697479894)

This will take you to the **Sign Up** page.

**Fill in the requested information,** and **click the Create Account button.**

![](https://cdn-learn.adafruit.com/assets/assets/000/125/219/medium800/adafruit_io_Create_Account_info_entered.png?1697479894)

This takes you to your Adafruit Account home page. From here, you can access all the features of your account.

You can also access the Adafruit content and services right from this page. Along the top of the page, you'll see a series of links beginning with "Shop". To access any of these, simply click the link.

![](https://cdn-learn.adafruit.com/assets/assets/000/125/217/medium800/adafruit_io_Create_account_home_page.png?1697479894)

For example, **to begin working with Adafruit IO, click the IO link** to the right of the rest of the links. This is the same for the other links as well.

That's all there is to creating a new Adafruit account, and navigating to Adafruit IO.

![](https://cdn-learn.adafruit.com/assets/assets/000/125/218/medium800/adafruit_io_Create_Account_io_homepage.png?1697479770)

# Ikea Vindriktning Hack with QT Py ESP32-S3 and Adafruit IO

## CircuitPython

[CircuitPython](https://github.com/adafruit/circuitpython) is a derivative of [MicroPython](https://micropython.org) designed to simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the **CIRCUITPY** drive to iterate.

## CircuitPython Quickstart

Follow this step-by-step to quickly get CircuitPython running on your board.

There are two versions of this board: one with 8MB Flash/No PSRAM and one with 4MB Flash/2MB PSRAM. Each version has their own UF2 build for CircuitPython. There isn't an easy way to identify which version of the board you have by looking at the board silk. If you aren't sure which version you have, try either build to see which one works.

Warning: 

[Download the latest version of CircuitPython for the 8MB/No PSRAM version of this board via circuitpython.org](https://circuitpython.org/board/adafruit_qtpy_esp32s3_nopsram/)
[Download the latest version of CircuitPython for the 4MB/2MB PSRAM version of this board via circuitpython.org](https://circuitpython.org/board/adafruit_qtpy_esp32s3_4mbflash_2mbpsram/)
 **Click the link above to download the latest CircuitPython UF2 file.**

Save it wherever is convenient for you.

![install_circuitpython_on_most_boards_CircuitPython_downloaded.jpg](https://cdn-learn.adafruit.com/assets/assets/000/102/129/medium640/install_circuitpython_on_most_boards_CircuitPython_downloaded.jpg?1620922559)

![](https://cdn-learn.adafruit.com/assets/assets/000/112/336/medium800/adafruit_products_cpTemplatePage.png?1655147030)

Plug your board into your computer, using a known-good data-sync cable, directly, or via an adapter if needed.

Click the **reset** button once (highlighted in red above), and then click it again when you see the **RGB status LED(s)** (highlighted in green above) turn purple (approximately half a second later). Sometimes it helps to think of it as a "slow double-click" of the reset button.

If you do not see the LED turning purple, you will need to reinstall the UF2 bootloader. See the&nbsp; **Factory Reset** &nbsp;page in this guide for details.

On some very old versions of the UF2 bootloader, the status LED turns red instead of purple.

For this board, tap reset and wait for the LED to turn purple, and as soon as it turns purple, tap reset again. The second tap needs to happen while the LED is still purple.

Once successful, you will see the **RGB status LED(s)** turn green (highlighted in green above), and a disk drive ending in " **...BOOT**" should appear on your host computer. If you see red, try another port, or if you're using an adapter or hub, try without the hub, or different adapter or hub.

If double-clicking doesn't work the first time, try again. Sometimes it can take a few tries to get the rhythm right!

A lot of people end up using charge-only USB cables and it is very frustrating! **Make sure you have a USB cable you know is good for data sync.**

Info: 

You will see a new disk drive appear called **QTPYS3**** BOOT**.

Drag the **adafruit\_circuitpython\_etc.uf2** file to **QTPYS3BOOT**.

![adafruit_products_drag_drop.png](https://cdn-learn.adafruit.com/assets/assets/000/112/384/medium640/adafruit_products_drag_drop.png?1655220237)

Copy or drag the UF2 file you downloaded to the **BOOT** drive.

The **BOOT** drive will disappear and a new disk drive called **CIRCUITPY** will appear.

That's it!

![install_circuitpython_on_most_boards_CIRCUITPY.jpg](https://cdn-learn.adafruit.com/assets/assets/000/102/130/medium640/install_circuitpython_on_most_boards_CIRCUITPY.jpg?1620923145)

# Ikea Vindriktning Hack with QT Py ESP32-S3 and Adafruit IO

## Create Your settings.toml File

CircuitPython works with WiFi-capable boards to enable you to make projects that have network connectivity. This means working with various passwords and API keys. As of [CircuitPython 8](https://circuitpython.org/downloads), there is support for a **settings.toml** file. This is a file that is stored on your **CIRCUITPY** drive, that contains all of your secret network information, such as your SSID, SSID password and any API keys for IoT services. It is designed to separate your sensitive information from your **code.py** file so you are able to share your code without sharing your credentials.

CircuitPython previously used a **secrets.py** file for this purpose. The **settings.toml** file is quite similar.

Warning: Your **settings.toml** file should be stored in the main directory of your **CIRCUITPY** drive. It should not be in a folder.

## CircuitPython **settings.toml** File

This section will provide a couple of examples of what your **settings.toml** file should look like, specifically for CircuitPython WiFi projects in general.

The most minimal **settings.toml** file must contain your WiFi SSID and password, as that is the minimum required to connect to WiFi. Copy this example, paste it into your **settings.toml** , and update:

- `your_wifi_ssid`
- `your_wifi_password`

```auto
CIRCUITPY_WIFI_SSID = "your_wifi_ssid"
CIRCUITPY_WIFI_PASSWORD = "your_wifi_password"
```

Many CircuitPython network-connected projects on the Adafruit Learn System involve using Adafruit IO. For these projects, you must _also_ include your Adafruit IO username and key. Copy the following example, paste it into your settings.toml file, and update:

- `your_wifi_ssid`
- `your_wifi_password`
- `your_aio_username`
- `your_aio_key`

```auto
CIRCUITPY_WIFI_SSID = "your_wifi_ssid"
CIRCUITPY_WIFI_PASSWORD = "your_wifi_password"
ADAFRUIT_AIO_USERNAME = "your_aio_username"
ADAFRUIT_AIO_KEY = "your_aio_key"
```

Some projects use different variable names for the entries in the **settings.toml** file. For example, a project might use `ADAFRUIT_AIO_ID` in the place of `ADAFRUIT_AIO_USERNAME`. **If you run into connectivity issues, one of the first things to check is that the names in the settings.toml file match the names in the code.**

Warning: Not every project uses the same variable name for each entry in the **settings.toml** file! Always verify it matches the code.

## **settings.toml** File Tips
Here is an example **settings.toml** file.

```auto
# Comments are supported
CIRCUITPY_WIFI_SSID = "guest wifi"
CIRCUITPY_WIFI_PASSWORD = "guessable"
CIRCUITPY_WEB_API_PORT = 80
CIRCUITPY_WEB_API_PASSWORD = "passw0rd"
test_variable = "this is a test"
thumbs_up = "\U0001f44d"
```

In a **settings.toml** file, it's important to keep these factors in mind:

- Strings are wrapped in double quotes; ex: `"your-string-here"`
- Integers are _ **not** _ quoted and may be written in decimal with optional sign (`+1`, `-1`, `1000`) or hexadecimal (`0xabcd`).
  - Floats (decimal numbers), octal (`0o567`) and binary (`0b11011`) are not supported.

- Use `\u` escapes for weird characters, `\x` and `\ooo` escapes are not available in **.toml** files
  - Example: `\U0001f44d` for 👍 (thumbs up emoji) and `\u20ac` for € (EUR sign)

- Unicode emoji, and non-ASCII characters, stand for themselves as long as you're careful to save in "UTF-8 without BOM" format

&nbsp;

&nbsp;

When your&nbsp; **settings.toml&nbsp;** file is ready, you can save it in your text editor with the **.toml** &nbsp;extension.

![adafruit_products_dotToml.jpg](https://cdn-learn.adafruit.com/assets/assets/000/117/071/medium640/adafruit_products_dotToml.jpg?1671034293)

## Accessing Your **settings.toml** Information in **code.py**
In your **code.py** file, you'll need to `import` the `os` library to access the **settings.toml** file. Your settings are accessed with the `os.getenv()` function. You'll pass your settings entry to the function to import it into the **code.py** file.

```python
import os

print(os.getenv("test_variable"))
```

![](https://cdn-learn.adafruit.com/assets/assets/000/117/072/medium800/adafruit_products_tomlOutput.jpg?1671034496)

In the upcoming CircuitPython WiFi examples, you'll see how the **settings.toml&nbsp;** file is used for connecting to your SSID and accessing your API keys.

# Ikea Vindriktning Hack with QT Py ESP32-S3 and Adafruit IO

## Code the Vindriktning

Once you've finished setting up your QT Py ESP32-S3 with CircuitPython, you can access the code and necessary libraries by downloading the Project Bundle.

To do this, click on the **&nbsp;Download Project Bundle** &nbsp;button in the window below. It will download to your computer as a zipped folder.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/Ikea_Vindriktning_QT_Py_ESP32-S3/code.py

## Upload the Code and Libraries to the QT Py ESP32-S3

After downloading the Project Bundle, plug your QT Py ESP32-S3 into the computer's USB port with a known good USB data+power cable. You should see a new flash drive appear in the computer's File Explorer or Finder (depending on your operating system) called&nbsp; **CIRCUITPY**. Unzip the folder and copy the following items to the QT Py ESP32-S3's&nbsp; **CIRCUITPY** &nbsp;drive.&nbsp;

- **lib** &nbsp;folder
- **code.py**

Your QT Py ESP32-S3&nbsp; **CIRCUITPY&nbsp;** drive should look like this after copying the&nbsp; **lib** &nbsp;folder and the&nbsp; **code.py&nbsp;** file.

![CIRCUITPY](https://adafruit.github.io/Adafruit_Learning_System_Guides/Ikea_Vindriktning_QT_Py_ESP32-S3.png )

## Add Your&nbsp; **settings.toml** File

As of CircuitPython 8, there is support for [Environment Variables](https://docs.circuitpython.org/en/latest/docs/environment.html). These Environmental Variables are stored in a **settings.toml** file. Similar to **secrets.py** , the **settings.toml** file separates your sensitive information from your main **code.py** file. Add your **settings.toml** file as described in the [Create Your settings.toml File page](https://learn.adafruit.com/ikea-vindriktning-hack-with-qt-py-esp32-s3-and-adafruit-io/create-your-settings-toml-file) earlier in this guide. You'll need to include your `CIRCUITPY_WIFI_SSID`, `CIRCUITPY_WIFI_PASSWORD`, `ADAFRUIT_IO_USERNAME` and `ADAFRUIT_IO_KEY` in the file.

```python
CIRCUITPY_WIFI_SSID = "your-wifi-ssid-here"
CIRCUITPY_WIFI_PASSWORD = "your-wifi-password-here"

ADAFRUIT_IO_USERNAME = "your-Adafruit-IO-username-here"
ADAFRUIT_IO_KEY = "your-Adafruit-IO-key-here"
```

## How the CircuitPython Code Works

First, the onboard NeoPixel is set up. Since you won't be able to see the serial monitor while the QT Py is inside the Vindriktning, the NeoPixel color will act as a status indicator.

```python
pixel_pin = board.NEOPIXEL
num_pixels = 1

pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.05, auto_write=False)
pixels.fill((255, 255, 0))
pixels.show()
```

## Connections

Then, the QT Py connects to WiFi and Adafruit IO. Both of these processes are wrapped in `try`/`except` statements to retry if any connection errors occur.

```python
try:
    wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD'))
except Exception as e:
    pixels.fill((100, 100, 100))
    pixels.show()
    print("Error:\n", str(e))
    print("Resetting microcontroller in 5 seconds")
    time.sleep(5)
    microcontroller.reset()

aio_username = os.getenv('ADAFRUIT_IO_USERNAME')
aio_key = os.getenv('ADAFRUIT_IO_KEY')

try:
    pool = socketpool.SocketPool(wifi.radio)
    requests = adafruit_requests.Session(pool, ssl.create_default_context())
    # Initialize an Adafruit IO HTTP API object
    io = IO_HTTP(aio_username, aio_key, requests)
    print("connected to io")
except Exception as e:
    pixels.fill((100, 100, 100))
    pixels.show()
    print("Error:\n", str(e))
    print("Resetting microcontroller in 5 seconds")
    time.sleep(5)
    microcontroller.reset()
```

## PM1006 Setup

The PM1006 sensor communicates over UART. Each packet of data from the PM1006 contains five measurements. You can tell the beginning of a packet based on the header values at the beginning of the UART data: `0x16`, `0x11` and `0x0B`. The `valid_header` function is used in the loop to determine if a new reading is coming in from the sensor.

```python
uart = busio.UART(board.TX, board.RX, baudrate=9600)

measurements = [0, 0, 0, 0, 0]
measurement_idx = 0

def valid_header(d):
    headerValid = (d[0] == 0x16 and d[1] == 0x11 and d[2] == 0x0B)
    # debug
    # if not headerValid:
        # print("msg without header")
    return headerValid
```

## The Loop

In the loop, every minute, the last PM2.5 data reading from the PM1006 sensor is logged to Adafruit IO. While data is being sent to Adafruit IO, the NeoPixel is blue.

```python
...
        data = uart.read(32)  # read up to 32 bytes
        #print(data)  # this is a bytearray type
        time.sleep(0.01)
        if ticks_diff(ticks_ms(), clock) &gt;= io_time:
            pixels.fill((0, 0, 255))
            pixels.show()
            io_data = measurements[0]
            if io_data != 0:
                io.send_data(ikea_pm25["key"], io_data)
                print(f"sent {io_data} to {ikea_pm25["key"]} feed")
            time.sleep(1)
            clock = ticks_add(clock, io_time)
            pixels.fill((0, 0, 0))
            pixels.show()
```

## Parsing Data

If data is read over UART, then the `valid_header` function determines if its the start of a new sensor reading array from the PM1006. If a new data series is being read, the NeoPixel turns red and the data is logged to the `measurements` array.

```python
...
            if data is not None:
            v = valid_header(data)
            if v is True:
                measurement_idx = 0
                start_read = True
            if start_read is True:
                pixels.fill((255, 0, 0))
                pixels.show()
                pm25 = (data[5] &lt;&lt; 8) | data[6]
                measurements[measurement_idx] = pm25
                if measurement_idx == 4:
                    start_read = False
                measurement_idx = (measurement_idx + 1) % 5
                print(pm25)
                print(measurements)
```

## Try, Try Again

When the QT Py is idle, the onboard NeoPixel is green. The entire loop is wrapped in a `try`/`except` statement so that the QT Py will reset in case of any errors.

```auto
try:

	...
    else:
      pixels.fill((0, 255, 0))
      pixels.show()
except Exception as e:
    print("Error:\n", str(e))
    print("Resetting microcontroller in 5 seconds")
    time.sleep(5)
    microcontroller.reset()
```

# Ikea Vindriktning Hack with QT Py ESP32-S3 and Adafruit IO

## Disassembly

![](https://cdn-learn.adafruit.com/assets/assets/000/122/151/medium800/hacks_edited_P1400832.png?1687898156)

Using a long and thin screwdriver, remove the four screws from the back of the air quality monitor.

![hacks_edited_P1400835.png](https://cdn-learn.adafruit.com/assets/assets/000/122/152/medium640/hacks_edited_P1400835.png?1687899419)

Slide out the front panel of the air quality monitor. You'll see the PM1006 module and fan plugged into the PCB.

![hacks_edited_P1400836.png](https://cdn-learn.adafruit.com/assets/assets/000/122/153/medium640/hacks_edited_P1400836.png?1687899782)

Unplug the PM1006 and fan connectors from the PCB.

![hacks_edited_P1400840.png](https://cdn-learn.adafruit.com/assets/assets/000/122/154/medium640/hacks_edited_P1400840.png?1687900093)

Remove the three screws mounting the PCB to the front panel.

![hacks_edited_P1400842.png](https://cdn-learn.adafruit.com/assets/assets/000/122/156/medium640/hacks_edited_P1400842.png?1687960880)

Lift the PCB out of the front panel. Now you're ready for soldering.

![hacks_edited_P1400845.png](https://cdn-learn.adafruit.com/assets/assets/000/122/157/medium640/hacks_edited_P1400845.png?1687960908)

# Ikea Vindriktning Hack with QT Py ESP32-S3 and Adafruit IO

## Soldering

![](https://cdn-learn.adafruit.com/assets/assets/000/122/158/medium800/hacks_edited_P1400854.png?1687960936)

You'll be soldering to three test points on the PCB: **5V** , **GND** and **REST**. They are located next to the plug for the PM1006 sensor and below the large capacitor on the PCB.

![hacks_edited_0P1400847.jpg](https://cdn-learn.adafruit.com/assets/assets/000/122/159/medium640/hacks_edited_0P1400847.jpg?1687961082)

Solder a piece of wire to each of the following test points: **5V** (red wire), **GND** (black wire) and **REST** (green wire).

![hacks_edited_P1400862.png](https://cdn-learn.adafruit.com/assets/assets/000/122/160/medium640/hacks_edited_P1400862.png?1687961106)

Solder the **5V** connection to the **BAT+** pad on the back of the QT Py (red wire). Then solder the **GND** connection to the **-** ( **GND** ) pad on the back of the QT Py (black wire).

![hacks_edited_P1410070.png](https://cdn-learn.adafruit.com/assets/assets/000/122/161/medium640/hacks_edited_P1410070.png?1687961141)

Solder the **REST** connection to the **RX** pin on the QT Py (green wire).

![hacks_edited_P1410072.png](https://cdn-learn.adafruit.com/assets/assets/000/122/162/medium640/hacks_edited_P1410072.png?1687961165)

# Ikea Vindriktning Hack with QT Py ESP32-S3 and Adafruit IO

## Reassembly and Hot Glue

Place the PCB back onto the front plate of the air quality monitor. Secure it with the three screws.

![hacks_edited_P1400868.png](https://cdn-learn.adafruit.com/assets/assets/000/122/163/medium640/hacks_edited_P1400868.png?1687961195)

Plug the PM1006 and fan connectors back into the PCB.

![hacks_edited_P1400870.png](https://cdn-learn.adafruit.com/assets/assets/000/122/164/medium640/hacks_edited_P1400870.png?1687961248)

Add a small dot of hot glue to the top of the inside of the case, above the PM1006 sensor. Press the QT Py into the hot glue to secure it with the USB port facing out. This way if you need to adjust the code, you can still access the USB port.

If you ever want to remove the QT Py, you can use some isopropyl alcohol to remove the hot glue.

![hacks_edited_P1410053.jpg](https://cdn-learn.adafruit.com/assets/assets/000/122/165/medium640/hacks_edited_P1410053.jpg?1687961359)

Close up the case with the four screws.

![hacks_edited_P1400877.png](https://cdn-learn.adafruit.com/assets/assets/000/122/166/medium640/hacks_edited_P1400877.png?1687961388)

Now you're ready to start logging the readings from the Vindriktning to Adafruit IO!&nbsp;

![hacks_edited_P1400880.png](https://cdn-learn.adafruit.com/assets/assets/000/122/167/medium640/hacks_edited_P1400880.png?1687961413)

# Ikea Vindriktning Hack with QT Py ESP32-S3 and Adafruit IO

## Adafruit IO Dashboard

![](https://cdn-learn.adafruit.com/assets/assets/000/122/168/medium800/hacks_hero.jpg?1687961531)

You can create a Dashboard in Adafruit IO to organize and display your data.

On Adafruit IO, click on the **Dashboards** tab and then **+ New Dashboard**.

![hacks__0.png](https://cdn-learn.adafruit.com/assets/assets/000/122/169/medium640/hacks__0.png?1687961553)

This opens the new Dashboard window. Enter the name of your Dashboard in the **Name** box and then click **Create**.

![hacks__1.png](https://cdn-learn.adafruit.com/assets/assets/000/122/170/medium640/hacks__1.png?1687961570)

 **Click** on the Dashboard you just created to view it.

![hacks__2.png](https://cdn-learn.adafruit.com/assets/assets/000/122/171/medium640/hacks__2.png?1687961589)

On the Dashboard, click the **cog wheel** and click **+ Create New Block**.

![hacks__3.png](https://cdn-learn.adafruit.com/assets/assets/000/122/172/medium640/hacks__3.png?1687961607)

Click on the **raw data** feed block and then **select the feed** from your feed list. Finally, you'll be brought to the block settings window, where you can name the block and adjust various settings.

![hacks_edited_4.jpg](https://cdn-learn.adafruit.com/assets/assets/000/122/173/medium640/hacks_edited_4.jpg?1687961818)

![hacks_edited_5.jpg](https://cdn-learn.adafruit.com/assets/assets/000/122/178/medium640/hacks_edited_5.jpg?1687961904)

![hacks__7.png](https://cdn-learn.adafruit.com/assets/assets/000/122/196/medium640/hacks__7.png?1688004645)

Then, create a second new block, this time selecting the **line graph** block.

![hacks_line_4.jpg](https://cdn-learn.adafruit.com/assets/assets/000/122/180/medium640/hacks_line_4.jpg?1687961935)

![hacks_edited_5.jpg](https://cdn-learn.adafruit.com/assets/assets/000/122/181/medium640/hacks_edited_5.jpg?1687961944)

![hacks__6.png](https://cdn-learn.adafruit.com/assets/assets/000/122/195/medium640/hacks__6.png?1688004645)

Now your Dashboard will show the raw data from the PM1006 and a line graph displaying the changes in the data over time.

![](https://cdn-learn.adafruit.com/assets/assets/000/122/182/medium800/hacks__8.png?1687961962)

# Ikea Vindriktning Hack with QT Py ESP32-S3 and Adafruit IO

## Adafruit IO Actions

Info: SMS message alerts are only available for IO+/IO Plus (Paid) accounts. To upgrade your Adafruit IO Free account to Adafruit IO Plus, visit [io.adafruit.com/plus](io.adafruit.com/plus)! Email notifications are available for free accounts.

You can set up Actions in Adafruit IO to alert you when certain values are logged. This can be especially handy for this project to let you know if your air quality is becoming unhealthy.

To receive an SMS message Action alert, you'll need to add your phone number to your Adafruit account. Note that SMS message alerts are only available for IO+ accounts. Other alert types are available for free tier accounts, such as email and web hooks.

![hacks_4.png](https://cdn-learn.adafruit.com/assets/assets/000/122/190/medium640/hacks_4.png?1687962446)

In Adafruit IO, go to the **Actions** tab and click on **+ New Action**.

![](https://cdn-learn.adafruit.com/assets/assets/000/138/085/medium640/hacks_uNoB5QTxmx.png?1751378939)

Enter a **Name** and optional description for the new Action, then click **Create.**

You'll be taken to the new Action page, with a Blockly toolbox and workspace.

![](https://cdn-learn.adafruit.com/assets/assets/000/138/106/medium640/hacks_oAlt4RRGqZ.png?1751403014)

All actions start with at least one **Trigger** block, placed into the top&nbsp;`Triggers:` section of the root block in the workspace.

1. Use the&nbsp; **data 'Starts' matching** trigger, so you can avoid being repeatedly notified.  
  
2. Drag it onto the root block, and then select the&nbsp; **feed** that you're monitoring from the list.  
  
3. Select the&nbsp; **greater than or equal** &nbsp;dropdown and enter the&nbsp; **value** &nbsp;that you want to monitor for the threshold

![Dragging a trigger block onto the Triggers section of the root block in the workspace](https://cdn-learn.adafruit.com/assets/assets/000/138/088/medium640thumb/hacks_chrome_qpj4u17faf.jpg?1751380770)

![](https://cdn-learn.adafruit.com/assets/assets/000/138/089/medium640/hacks_vPiDLqpNQe.png?1751380705)

![](https://cdn-learn.adafruit.com/assets/assets/000/138/090/medium640/hacks_Screenshot_2025-07-01_153645.png?1751380743)

Now the trigger is done, you'll want to get the data into a new variable, to make it easier to use later in the template.

1. Create a **new variable** in the toolbox, named `my-data`, then drag the **Set Variable** block onto the main diagram, dropping it into the `Actions:` section of the root block.  
  
2. From the **Feeds** toolbox category, drag a **Get Feed** block over to the Set Variable block, and connect them horizontally, so that the Set Feed block replaces the empty placeholder text block as the value to be set.

![](https://cdn-learn.adafruit.com/assets/assets/000/138/091/medium640thumb/hacks_chrome_evgQ7kFjcU.jpg?1751381915)

Lastly use a Send SMS block from the Notifications toolbox category. Drop it beneath the Set Variable block, and **customize the message** that you'll receive when the action is triggered.

Try this for a message, which uses the `map` [filter](https://shopify.github.io/liquid/filters/map/) in Liquid templates, to access the **updated\_at** timestamp property (in UTC). Mapped from the **first** feed used in the action (via the `feeds` placeholder). It also includes the variable&nbsp; **my-data** under the `vars` placeholder.

`⚠️Ikea AQ Sensor Detected an Unhealthy Value:{{vars.my-data}}ppm at {{ feeds | first | map: "updated_at" }}`

![](https://cdn-learn.adafruit.com/assets/assets/000/138/092/medium640thumb/hacks_chrome_QfRcZeiu9e.jpg?1751382209)

Finally click the **Save** button to save the Action. Choose&nbsp; **Enable and Save** if asked.

![](https://cdn-learn.adafruit.com/assets/assets/000/138/093/medium640/hacks_ZD6vCkWuHo.png?1751382333)

This returns you to the Action page, where you can see the Action you just set up.

There is also an **Enable** toggle switch (On or Off), and an information icon at the end of the row.

![](https://cdn-learn.adafruit.com/assets/assets/000/138/104/medium640/hacks_z9ymBivVUv.png?1751402611)

When the Action is triggered, you'll receive the notification with the message that you entered.

![hacks_edited_Screenshot_2023-06-28_at_10.29.49_AM.jpg](https://cdn-learn.adafruit.com/assets/assets/000/122/194/medium640/hacks_edited_Screenshot_2023-06-28_at_10.29.49_AM.jpg?1688003578)

# Ikea Vindriktning Hack with QT Py ESP32-S3 and Adafruit IO

## Use

![](https://cdn-learn.adafruit.com/assets/assets/000/122/220/medium800/hacks_edited_P1410090.png?1688150872)

Warning: This project has only been tested with a QT Py ESP32-S3. Other boards may not work as expected.

Plug in the&nbsp;Vindriktning to a USB C cable and power supply. The QT Py ESP32-S3 will receive power from the PCB and run the CircuitPython code.

Over time, you'll see the PM2.5 data from the PM1006 sensor inside the&nbsp;Vindriktning be logged to Adafruit IO.

![hacks_hero.jpg](https://cdn-learn.adafruit.com/assets/assets/000/122/199/medium640/hacks_hero.jpg?1688006697)

If the air quality rises above your defined threshold, the Action you set up will be triggered and you'll receive an alert.

![hacks_edited_Screenshot_2023-06-28_at_10.29.49_AM.jpg](https://cdn-learn.adafruit.com/assets/assets/000/122/200/medium640/hacks_edited_Screenshot_2023-06-28_at_10.29.49_AM.jpg?1688006813)


## Featured Products

### Adafruit QT Py ESP32-S3 WiFi Dev Board with STEMMA QT

[Adafruit QT Py ESP32-S3 WiFi Dev Board with STEMMA QT](https://www.adafruit.com/product/5426)
The ESP32-S3 has arrived in QT Py format - and what a great way to get started with this powerful new chip from Espressif! With dual 240 MHz cores, WiFi and BLE support, and native USB, this QT Py is great for powering your IoT projects.

The ESP32-S3&nbsp;is a highly-integrated,...

Out of Stock
[Buy Now](https://www.adafruit.com/product/5426)
[Related Guides to the Product](https://learn.adafruit.com/products/5426/guides)
### Silicone Cover Stranded-Core Wire - 30AWG in Various Colors

[Silicone Cover Stranded-Core Wire - 30AWG in Various Colors](https://www.adafruit.com/product/2051)
Silicone-sheathing wire is super-flexible and soft, and its also strong! Able to handle up to 200°C and up to 600V, it will do when PVC covered wire wimps out. We like this wire for being extremely supple and flexible, so it is great for wearables or projects where the wire-harness has to...

Out of Stock
[Buy Now](https://www.adafruit.com/product/2051)
[Related Guides to the Product](https://learn.adafruit.com/products/2051/guides)
### Pink and Purple Woven USB A to USB C Cable - 2 meters long

[Pink and Purple Woven USB A to USB C Cable - 2 meters long](https://www.adafruit.com/product/5044)
This cable is not only super-fashionable, with a woven pink and purple Blinka-like pattern, it's also made for USB C for our modernized breakout boards, Feathers and more.&nbsp; [If you want something just like it but for Micro B, we have a B...](https://www.adafruit.com/product/4111)

Out of Stock
[Buy Now](https://www.adafruit.com/product/5044)
[Related Guides to the Product](https://learn.adafruit.com/products/5044/guides)
### Adafruit IO+ Subscription Pass – One Year

[Adafruit IO+ Subscription Pass – One Year](https://www.adafruit.com/product/3792)
The all-in-one Internet of Things service from Adafruit you know and love is now _even better_ with IO+. The 'plus' stands for MORE STUFF! More feeds, dashboards, storage, speed. Power up your [Adafruit IO](https://io.adafruit.com/) with the $99 pass for 1 year of the...

In Stock
[Buy Now](https://www.adafruit.com/product/3792)
[Related Guides to the Product](https://learn.adafruit.com/products/3792/guides)

## Related Guides

- [Adafruit QT Py ESP32-S3](https://learn.adafruit.com/adafruit-qt-py-esp32-s3.md)
- [Adafruit IO Basics: Analog Input](https://learn.adafruit.com/adafruit-io-basics-analog-input.md)
- [Adafruit IO Basics: Analog Output](https://learn.adafruit.com/adafruit-io-basics-analog-output.md)
- [Adafruit IO Basics: Dashboards](https://learn.adafruit.com/adafruit-io-basics-dashboards.md)
- [No-Code IKEA Vindriktning Air Quality Sensor Hack with Adafruit IO](https://learn.adafruit.com/no-code-ikea-vindriktning-hack-with-qt-py-esp32-s3-and-adafruit-io.md)
- [Use Apple HomeKit Devices with itsaSNAP and Adafruit IO](https://learn.adafruit.com/use-apple-homekit-devices-with-itsasnap.md)
- [How to use Blockly for Actions on Adafruit IO](https://learn.adafruit.com/how-to-use-blockly-for-actions-on-adafruit-io.md)
- [Adafruit IO Basics: Digital Output](https://learn.adafruit.com/adafruit-io-basics-digital-output.md)
- [Where's My Friend? A Location-Aware Display with PyPortal and ItsASnap](https://learn.adafruit.com/where-s-my-friend-a-location-display-frame-with-pyportal.md)
- [Adafruit IO Basics: Feeds](https://learn.adafruit.com/adafruit-io-basics-feeds.md)
- [Canary Nightlight ](https://learn.adafruit.com/canary-nightlight.md)
- [itsaSNAP Daily Weather Forecast Board](https://learn.adafruit.com/itsasnap-daily-weather-forecast-board.md)
- [Tiny LED WiFi Companion Cube](https://learn.adafruit.com/tiny-led-wifi-cube.md)
- [CircuitPython Webcam with OV2640](https://learn.adafruit.com/circuitpython-webcam-with-ov2640.md)
- [Quick Start: Pico W / 2W with WipperSnapper](https://learn.adafruit.com/quick-start-the-pico-w-with-wippersnapper.md)
