logging

Thursday, October 19, 2023

IKEA VINDSTYRKA and Raspberry Pi

Introduction


IKEA is a Swedish multinational conglomerate that designs and sells ready-to-assemble furniture, kitchen appliances, decoration, home accessories, and various other goods and home services. Since 2016 IKEA also moved into the 'smart home' business. The smart home offering consists of devices like lamps, speakers, air purifiers, various sensors and an infrastructure of hubs and an app to glue things together.

Here I want to focus on VINDSTYRKA, this is a device to monitor, and report, air quality. My objective is reading information from the device using a Raspberry Pi and store the readings in a database.

The device shows up in the IKEA Home smart app as:
The VINDSTYRKA display shows real time information regarding fine particles or 'particulate matter 2.5' (PM2.5), temperature, humidity and an indication of total volatile organic compounds (tVOC). The information displayed on 'tVOC' is limited to 'arrow up' (rising), 'arrow horizontal' (static) or 'down' (quality improving).
Inside the VINDSTYRKA is a sensor: Sensirion SEN54 sensor. The manufacturers specifications provide more insight into the device capabilities.

VINSTYRKA and IKEA Home smart


Since this sensor is part of IKEA smart home it can be coupled to an IKEA smart home network via a DIRIGERA hub. The communication between the VINDSTYRKA and DIRIGERA hub uses a protocol called Zigbee, the DIRIGERA hub can be accessed via 'ordinary' TCP/IP. This connectivity opens up the possibility of building your own sensor applications. Below is a diagram of the topology now used by me:

Raspberry Pi setup

To gather information from the VINSTYRKA I use a Raspberry Pi running the desktop version of Ubuntu 22.04.3 LTS at the time of writing. Both hardware and operating system choices are not really important , many other combinations may work as well.
On the system as a normal user I setup a directory for the software:
python3 -m venv dirigera
cd dirigera/
source bin/activate
Some explanation:
  • When installing Python packages you should always do this in a virtual environment. My personal prefence is to create create the environment with the name of my project so the prompt shows the name of the active project. In my case:
    jvdmeiden@pi001:~/projects/dirigera$ source bin/activate
    (dirigera) jvdmeiden@pi001:~/projects/dirigera$
    

Then install the dirigera package from https://github.com/Leggin/dirigera:
pip install dirigera
And generate the token for your DIRIGERA using the instructions on https://github.com/Leggin/dirigera:
generate-token <IP address of your DIRIGERA>
Save the generated token in a text file for future use.

Create a database to store information read from the VINDSTYRKA(s)

Create a database for the data from the VINDSTYRKA(s) in your environment (in my case) called 'measurement.db:
sqlite3 measurements.db
Within the database create a table for the measurements:
CREATE TABLE sensor_measurement(timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, room TEXT, temperature INT, humidity  INT,
 pm2_5 INT, tvoc INT);

Create a Python application to read from the VINDSTYRKA(s)

Start out with a script that connects to the hub and reads and prints the sensors information:
import dirigera
hub = dirigera.Hub(
  hub = dirigera.Hub(
  token="..........YOUR..TOKEN.........................................................................",
  ip_address="<IP Address of your DIRIGERA>"
)

current = hub.get_environment_sensors()
for i in range(len(current)):
    print(current[i]);
In my case I have 2 VINDSTYRKA's attached to the DIRIGERA and I get the following output:
EnvironmentSensor(
  device_id='519f42da-bd69-4229-94bf-9c6d1eab4c24_1', 
  custom_name='', 
  room_id='bf0f1f49-7d4b-4116-84d7-78c8c357eac5', 
  room_name='Living room', 
  firmware_version='1.0.11', 
  hardware_version='1', 
  model='VINDSTYRKA', 
  manufacturer='IKEA of Sweden', 
  serial_number='90AB96FFFEF89CA1', 
  can_receive=['customName'], 
  dirigera_client=, 
  is_reachable=True, 
  current_temperature=18, current_rh=75, 
  current_pm25=5, 
  max_measured_pm25=999, 
  min_measured_pm25=0, 
  voc_index=387
)
EnvironmentSensor(
  device_id='dd210409-c149-4e0c-9516-4601cb6b42c8_1', 
  custom_name='Sensor 2', 
  room_id='6dd81fa8-11d9-4a86-8a8a-b465d721df54', 
  room_name='Attick', 
  firmware_version='1.0.11', 
  hardware_version='1', 
  model='VINDSTYRKA', 
  manufacturer='IKEA of Sweden', 
  serial_number='287681FFFE67EC46', 
  can_receive=['customName'], 
  dirigera_client=, 
  is_reachable=True, 
  current_temperature=18, 
  current_rh=70, 
  current_pm25=4, 
  max_measured_pm25=999, 
  min_measured_pm25=0, 
  voc_index=51
)
The information contains the room names I gave the VINDSTARKA's and which data is sent back, the interesting part is:
  • room_name: the name you gave to the VINDSTYRKA
  • current_temperature
  • current_rh (humidity)
  • current_pm25 (PM2.5: fine inhalable particles, with diameters 2.5 micrometers and smaller)
  • max_measured_pm25 and min_measured_pm25=0: the minimal and maximal values of current_pm25
  • voc_index: total volatile organic compounds (tVOC)
It is very interesting that the tvoc information is much more than the simple 'arrow up', 'down' or 'horizontal', shown by the VINDSTYRKA display and the IKEA Home smart app. The information now is an integer in range 1..250. The default value is 100.
To store relevant information in the database create a Python script (I call mine 'sensors.py'):
import dirigera
import sqlite3

conn = sqlite3.connect('<Path to your project directory>/measurements.db')
cursor = conn.cursor()

hub = dirigera.Hub(
  token="..........YOUR..TOKEN.........................................................................",
  ip_address="<IP Address of your DIRIGERA>"
)
current = hub.get_environment_sensors()
for i in range(len(current)):
  cursor.execute('''INSERT INTO sensor_measurement(room,temperature,humidity,pm2_5,tvoc)
    VALUES (?,?,?,?,?)''',
    [current[i].room_name,current[i].current_temperature,current[i].current_rh,current[i].current_pm25,current[i].voc_in
dex])
  conn.commit()
conn.close()
The logic is pretty basic:
  • import the required packages
  • create a hub object
  • connect to the DIRIGERA and get sensor information
  • the returned information is an array of values for each sensor known by the DIRIGERA
  • insert the information for each sensor into the database table


Schedule gathering information using 'cron'

In order to gather information over longer regular intervals create a bash script (sensors.sh) that sets the environment and runs the Python script:
#!/bin/bash
source <Path to your project directory>/bin/activate
python3 <Path to your project directory>/sensors.py
Then create a crontab entry using 'crontab -e':
# m h  dom mon dow   command
  */20  *  *  *  *  <Path to your project directory>/sensors.sh 2>&1 | logger
This will run the script every 20 minutes.
For debugging it is usefull to have the the cronjob write errors to 'logger', the syslog will give a hint of what went wrong in case of problems.

Making sense of the gathered data


After some time the database will contain gathered data like:
sqlite> select * from sensor_measurement where room = 'Living room';
2023-11-19 12:20:02|Living room|18|66|5|59
2023-11-19 12:40:02|Living room|18|66|5|57
2023-11-19 13:00:02|Living room|18|67|5|58
2023-11-19 13:20:02|Living room|18|67|5|61
2023-11-19 13:40:03|Living room|18|67|6|67
2023-11-19 14:00:02|Living room|18|67|6|63
2023-11-19 14:20:02|Living room|18|67|6|58
2023-11-19 14:40:02|Living room|18|67|6|58
2023-11-19 15:00:02|Living room|18|67|7|65
2023-11-19 15:20:02|Living room|18|68|5|168
2023-11-19 15:40:02|Living room|18|75|7|376
2023-11-19 16:00:02|Living room|18|76|8|396
2023-11-19 16:20:02|Living room|18|76|7|360
2023-11-19 16:40:02|Living room|18|75|7|312
2023-11-19 17:00:02|Living room|19|75|6|319
2023-11-19 17:20:02|Living room|19|74|5|103
2023-11-19 17:40:02|Living room|19|76|7|102
2023-11-19 18:00:03|Living room|19|76|7|97
2023-11-19 18:20:02|Living room|19|77|6|108
2023-11-19 18:40:02|Living room|19|76|6|71
2023-11-19 19:00:02|Living room|19|76|5|60
2023-11-19 19:20:02|Living room|19|75|6|43
In this case it shows the increase in tVOC, that coincides with cooking and is not something to get alarmed about.

The peak in tVOC can be plotted as a graph:


Conclusion

Using a DIRIGERA hub and a RASPBERRY Pi it is relativly easy to gather data from the VINDSTYRKA for analysis.

To be continued

The following items are on my to-do list:
  • Gather data from multiple VINDSTYKA sensors and compare them.
  • Correlate the data from the VINDSTYRKA's with weather data.
  • Circumvent the DIRIGERA by connecting at Zigbee level.
  • Replace the VINDSTYRKA by the sensor that is inside Sensirion SN54.
  • Better understand the meaning of various values like tVOC by placing the sensor in a confined space and expose it to things like alcohol vopor, smoke, et cetera.
  • Create a front end that shows the information in graphs.


Links:

Introduction to OpenLayers

Introduction What is 'OpenLayers'? Openlayers is an open-source JavaScript library for displaying maps and map data in web brow...