IKEA TRÅDFRI for Rebooting a Server or Modem

Recently I revamped my home internet, and (hopefully) temporarily ended up with a modem that needs to be power cycled from time to time. We’re working on getting it fixed, but in the meantime I needed a solution for automated power cycling.

There are various ways to turn the power off or on from a Linux computer, and some of these are very karmic. You can get a zigbee USB stick and ditto power plugs, and I am sure this is a lot of fun.

But I wasn’t looking for a fun hacking product, I wanted a quick fix. Friends recommended that I look into the IKEA TRÅDFRI stuff. On the whole, it appears my friends were somewhat optimistic, but I still love them.

On the surface of it, the solution does indeed look neat. And, the good news is, after only 30 minutes of swearing I got it working. Fixing up the remaining problems took several hours.

Note, I do think IKEA TRÅDFRI is pretty nice for its intended purpose. No blame to the IKEA developers, who are nice enough to email open source projects with tips. The security also looks good (and is the main reason for the 30 minutes of swearing). Also, because this is a very large scale consumer brand, we don’t have to worry about the electrical safety either.

I’m not a ‘domotics’ expert and I very much don’t want to be. But if you already have IKEA TRÅDFRI equipment, or simply want to do exactly what I did to solve your problem, do read on.

Update: Jan-Piet Mens suggested this Wifi-controlled alternative, the Delock WLAN Power Socket Switch MQTT which gets the job done with no further moving parts, for only 15 euros. Jan-Piet also wrote a review that is worth your time. There is even a plug that also measures power consumption.

If you are impatient, skip to the very end where you’ll find a ready to use script.

Requirements

The IKEA stuff I used:

I actually only bought the remote control because I thought it might be fun. Turns out it is a mandatory part of the solution.

You might be able to save some money and order this one instead of the first two items, but I have not tried this:

You’ll also need an Android compatible device (might work on some Chromebooks, not sure) or an iPhone or an iPad.

How it hangs together

The Gateway, also known as the Hub, has ethernet. It also has a micro-usb port for power, which is nice, I power it from one of my computers, which saves a power plug. It will automatically request an IPv4 address over DHCP.

On the bottom of the gateway is a QR code that lists a secret key. It is also printed in plaintext. IKEA demands that you do not store this secret key permanently in your application. But we’re going to do that anyhow.

Plug the gateway in, and install the TRÅDFRI app on a phone or tablet that is on the same ethernet/wifi segment.

The remote control

Put the battery in the remote control. Next up, follow the instructions in the app to add the remote control. This part is key. The app suggests you can also enroll your power plug (“control outlet”) without the remote, but this is not true. The remote control goes first. There are clear on screen instructions on how you should push the button on the remote, and how to hold it close to the hub.

Only proceed once the remote control and the app are friends.

The control outlet / power plug

Next up, a new menu appears in the app where you can add the control outlet. There are no buttons to press on this outlet. But there is a button to press on the remote. The remote control actually helps pair your plug with the Gateway.

Plug the control outlet into a wall socket, and do the button press ritual on the remote. I’m not documenting it here because it could change. The app will tell you what to do.

At this point, you should be able to turn power on and off from both the remote control and the app.

Controlling the whole thing from your computer

You need to do the following to get functional “Constrained Application Protocol” tooling with DTLS support:

sudo apt-get install build-essential autoconf automake libtool
git clone https://github.com/obgm/libcoap
cd libcoap
./autogen.sh
./configure --with-openssl --disable-doxygen --disable-manpages
make
sudo make install

You may have to change the first and last lines depending on your UNIX version.

NOTE! An earlier version of this page listed outdated instructions for compiling coap-client. This led to a very suboptimal experience. This modern version is a lot better.

Also note that Linux distributions do ship coap-client, but this then lacks DTLS encryption support.

Next up, you need to find the IP address of the Gateway. Consult your DHCP logs. The device listens on port 80, but so do many devices - you can’t easily nmap it.

On the back of the device you’ll find a secret key. You need to use this to create a preshared key:

TF_USERNAME=user1
TF_GATEWAYCODE=whateverwasonthesticker
TF_GATEWAYIP=192.168.1.88
examples/coap-client -m post -u "Client_identity" -k "$TF_GATEWAYCODE" -e "{\"9090\":\"$TF_USERNAME\"}" "coaps://$TF_GATEWAYIP:5684/15011/9063" | grep 9091

This will print a response somewhat like this:

{"9091":"XFvk5DraRgaThbir","9029":"1.11.0051"}

9091 is the preshared key, 9029 the device firmware version.

If we pipe this through cut -f4 -d\", we get the key. We’ll store this in TF_PRESHARED_KEY.

Next up, we can use the key to get a list of devices:

/examples/coap-client -m get -u "$TF_USERNAME" -k "$TF_PRESHARED_KEY" "coaps://$TF_GATEWAYIP:5684/15001" -v 0
v:1 t:CON c:GET i:fbcf {} [ ]
[65536,65537]

The first device is our remote, which we aren’t going to do anything with. The second one is the power switch.

To turn power on or off, use:

TF_DEVICEID=65537
TF_POWERSTATE=1 # or 0
./examples/coap-client -m put -u "$TF_USERNAME" -k "$TF_PRESHARED_KEY" -e "{ \"3312\": [{ \"5850\": $TF_POWERSTATE }] }" "coaps://$TF_GATEWAYIP:5684/15001/$TF_DEVICEID"

And that’s it. I don’t entirely know what the numbers in there mean. 3312 is probably some group, and 5850 is then probably the power state within that.

The pre-shared key problem

The preshared key we received expires after six weeks, I am told. This period is extended everytime you issue a command.

But if you don’t turn anything on or off for six weeks, your preshared key is dead.

Now, we could attempt to get a fresh PSK using the Gateway secret key, but the API does not support that. If you ask for a new preshared key and the device reckons you already had one, it won’t give you a new PSK.

The only solution I have found to test if your PSK is still valid is to attempt to do something. If the PSK was wrong, the thing does not happen. coap-client then does not set a useful error code.

So what I do is ask the Gateway for a list of devices, and grep for the remote control (65536). If that is not in there, I assume the PSK is wrong and I request a new one, and hope that one works.

Here is the full script. If you run it without a parameter, it will list any device numbers paired to the Gateway. If you call it with ‘1’ it will turn on the power of device 65537, if you call it with ‘0’ it will turn it off. The PSK is stored in the current working directory in a file called ‘tradfri.psk’.

#!/bin/bash

TF_USERNAME=user
TF_GATEWAYCODE="fromthesticker"
TF_GATEWAYIP=fromdhcp
TF_DEVICEID=65537

function getnewpsk {
 echo Getting a new pre-shared key
 examples/coap-client -m post -u "Client_identity" -k "$TF_GATEWAYCODE" -e "{\"9090\":\"$TF_USERNAME\"}" "coaps://$TF_GATEWAYIP:5684/15011/9063" | grep 9091 | \
 cut -f4 -d\" > tradfri.psk
}

if [ \! -s tradfri.psk ]
then
 getnewpsk
else
 echo Reusing earlier pre-shared key
fi

TF_PRESHARED_KEY=$(cat tradfri.psk)

echo TF_PRESHARED_KEY is ${TF_PRESHARED_KEY}


echo testing PSK
examples/coap-client -B 1 -m get -u "$TF_USERNAME" -k "$TF_PRESHARED_KEY" "coaps://$TF_GATEWAYIP:5684/15001" | grep 65537
if [ "$?" = "1" ]
then 
        echo PSK was wrong, requesting a new one
        getnewpsk
        TF_PRESHARED_KEY=$(cat tradfri.psk)
else
        echo PSK was ok
fi

# possibly flip power state 
if [ \! -z "$1" ] 
then 
        echo Going to set powerstate to $1

        TF_POWERSTATE=$1
        ./examples/coap-client -m put -u "$TF_USERNAME" -k "$TF_PRESHARED_KEY" -e "{ \"3312\": [{ \"5850\": $TF_POWERSTATE }] }" "coaps://$TF_GATEWAYIP:5684/15001/$TF_DEVICE
fi