Return to front page

Controlling IKEA Trådfri light using Raspberry Pi

In this article I will explain how I created a simple wake-up light from an IKEA smartbulb that relies on Zigbee2MQTT running on a Raspberry Pi

Instead of doing the Azure project I had planned, I've been studying for the AZ-204 certificate on my free time. I decided to use my first vacation day to start and surprisingly finish a project that has been on my mind ever since I bought the Raspberry Pi. We have an IKEA Trådfri lamp in our bedroom and I wanted to turn it into a make shift wake-up light.

The tools

Not knowing at all what I was doing I started googling and found Zigbee2MQTT, which supports IKEA lightbulbs and remote control out of the box. As the name suggests, it also provides an MQTT setup which can be used to publish messages to the control topics. I will be using moquitto_pub to send control messages.

I then needed a Zigbee stick to connect the Raspberry Pi to the IKEA devices, and basically bought the first thing that I found in stock. It was a SONOFF Zigbee 3.0 USB dongle.

And of course I needed my trusty Raspberry Pi model 3 b+ and something to control with it. Supported devices can be found from here.

Setting up the environment

First thing I did was start from the Getting started page of the Zigbee2MQTT. I already had docker installed on my Raspberry so I could jump straight in. Finding the device location after plugging in my dongle was easy, as it printed the whole name of the device:

mituuz@raspberrypi:~ sudo dmesg | grep -A 5 -B 5 'Zigbee'

[764059.436555] usb 1-1.2: new full-speed USB device number 5 using dwc_otg 
[764059.592285] usb 1-1.2: Product: SONOFF Zigbee 3.0 USB Dongle Plus V2 
[764059.592298] usb 1-1.2: Manufacturer: ITEAD 
[764060.112726] cdc_acm 1-1.2:1.0: ttyACM0: USB ACM device 
[764060.113028] usbcore: registered new interface driver cdc_acm 
[764060.113047] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters 

mituuz@raspberrypi:~ $ ls -ltr /dev/ttyACM0 crw-rw---- 1 root dialout 166, 0 Jun 26 20:16 /dev/ttyACM0

Instead of worrying about the Zigbee networking adapters I could just get the container running. Replacing the device location in the docker-compose file and using a different port for the Zigbee2MQTT frontend as I already had something running on the 8080 port.

version: '3.8'
services:
    mqtt:
        image: eclipse-mosquitto:2.0
        restart: unless-stopped
        volumes:       
            - "./mosquitto-data:/mosquitto"
        ports:       
            - "1883:1883"
            - "9001:9001"
        command: "mosquitto -c /mosquitto-no-auth.conf"

    zigbee2mqtt:
        container_name: zigbee2mqtt
        restart: unless-stopped
        image: koenkk/zigbee2mqtt
        volumes:
            - ./zigbee2mqtt-data:/app/data
            - /run/udev:/run/udev:ro
        ports:
            - 8088:8088
        environment:
            - TZ=Europe/Helsinki
        devices:
            - /dev/ttyACM0:/dev/ttyACM0

The port and serial had to be changed to match on the configuration.yaml.

permit_join: true
mqtt:
  base_topic: zigbee2mqtt
  server: mqtt://mqtt
  keepalive: 60
  reject_unauthorized: true
  version: 4
serial:
  port: /dev/ttyACM0
frontend:
  port: 8088

Then I could start the docker containers and access the Zigbee2MQTT frontend from the port 8088 of the Raspberry Pi and connect the devices as instructed on the supported devices page.

To manually insert messages to the MQTT topic I installed mosquitto and mosquitto-clients.

sudo apt-get update
sudo apt-get install mosquitto mosquitto-clients

When testing the initial setup I noticed that you can't have the light connecting to the remote and the Raspberry at the same time. To overcome this limitation I had to connect the remote to the Raspberry too. Using the bind functionality the remote could be used to control the light normally. This functionality was covered on the remote's page itself.

Creating the script and setting up the cronjob

I spent some time playing with the frontend and mosquitto messages and found out that I could control the transition time of the light. This would make creating a wake-up light effect extremely easy. Instead of updating the values incrementally I could change the transition timer and update the brightness value of the light once.

I had some issues getting the messages to work, but after some digging and asking ChatGPT for help it pointed out that I was sending the messages to localhost instead of the docker container. To solve this, I populate an env variable at the beginning of the script.

MQTT_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' zigbeelights-mqtt-1)

With this I could create a script that:

Replace the {friendly_name} with the actual device name set on the frontend (or id).

echo 'Wakey wakey' $(date +"%Y-%m-%d %H:%M")

# Get the IP address of the docker container
MQTT_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' zigbeelights-mqtt-1)

# Reset the light parameters
mosquitto_pub -h $MQTT_IP -t zigbee2mqtt/{friendly_name}/set -m '{"color_temp": 250, "brightness": 2, "color":{"x": 0.3804, "y": 0.3767}}'

# Turn on the light
mosquitto_pub -h $MQTT_IP -t zigbee2mqtt/{friendly_name}/set -m '{"state": "ON"}'

# Change transition time (30min)
mosquitto_pub -h $MQTT_IP -t zigbee2mqtt/bridge/request/device/options -m '{"id": "{friendly_name}", "options":{"transition":1800}}'

# Set brightness to max
mosquitto_pub -h $MQTT_IP -t zigbee2mqtt/{friendly_name}/set -m '{"brightness": 254}'

# Set a bash timer and log progress
sleep 450
echo 'Quarter of the way there' $(date +"%Y-%m-%d %H:%M")

sleep 450
echo 'Halfway point' $(date +"%Y-%m-%d %H:%M")

sleep 450
echo 'Almost there' $(date +"%Y-%m-%d %H:%M")

sleep 450

# Change the transition time back to instant
mosquitto_pub -h $MQTT_IP -t zigbee2mqtt/bridge/request/device/options -m '{"id": "{friendly_name}", "options":{"transition":0}}'
echo 'Wake up complete' $(date +"%Y-%m-%d %H:%M")

I wanted to have some logging so I included the echo commands and setup my cronjob to output to a log file. I setup three cronjobs for different days of the week.

30 4 * * 1,3-5 /home/mituuz/Projects/ZigbeeLights/morning-light.sh > /home/mituuz/Projects/ZigbeeLights/morning.log 2>&1
40 6 * * 2 /home/mituuz/Projects/ZigbeeLights/morning-light.sh > /home/mituuz/Projects/ZigbeeLights/morning.log 2>&1
40 7 * * 6-7 /home/mituuz/Projects/ZigbeeLights/morning-light.sh > /home/mituuz/Projects/ZigbeeLights/morning.log 2>&1

This is just one application for the Zigbee2MQTT that could be used and the supported devices list seemed to be quite long. I will definitely be coming back and seeing what else I could do with this setup.

Return to front page