Info

This post is a part of a bigger project. You can read about it all here:

  1. Control Ikea Idasen standing desk from Raspberry Pi
  2. DYI Macro Keyboard on Linux, à la Elgato Stream Deck

Physical controls of IKEA Idasen standing desk allow it to move up and down, but lack the ability to save any positions. While it is possible to connect via Bluetooth and save favourite heights in the app, switching between them requires us to still tap and hold the button there. The desk stops moving when button is released. I’m not sure what dictated that design decision, as the desk is capable of detecting obstructions and can stop itself from moving even if the user is still pressing the controls (don’t ask me how I know this). I would therefore like to just press the button once and let the desk do its thing. This got me thinking if there are any hackable solutions out there, and indeed there’s even more than one.

Introducing:

NameLink
idasen-controllerhttps://github.com/rhyst/idasen-controller
idasenhttps://github.com/newAM/idasen
esphome-idasen-desk-controllerhttps://github.com/j5lien/esphome-idasen-desk-controller

Kudos to their creators. I chose to use the first one, idasen-controller.

I have a spare Raspberry Pi 3B+, which I’ll be using later to setup AirPlay streaming in my office, so I may as well use it for controlling my desk. I’m also planning to tie it all together with a nice Numpad controller, inspired by this YouTube video from David Zhang. Stay tuned!

I’m using the official distribution based on Debian 11 (Bullseye), specifically the x64 lite variant without desktop environment - Raspberry Pi OS Lite x64. I initially tried to set it up with Ubuntu Server, but I couldn’t get Bluetooth working reliably (it’s a real PITA sometimes). I didn’t want to sink more hours into this project (I have other things to do! 😝), so I reverted to official Raspberry Pi OS distribution. It works there.

Connecting via Bluetooth from Raspberry Pi

It’s quick and simple (when it works). First, run bluetoothctl. You should see an active Bluetooth adapter / controller and the prompt will change to [bluetooth]#:

$ bluetoothctl
Agent registered
[CHG] Controller B8:27:EB:XX:XX:XX Pairable: yes
[bluetooth]#

At this point, you need to put the desk controller in pairing mode. Hold the Bluetooth pairing button until its blue LED starts rapidly flashing. Now we can scan for devices with:

[bluetooth]# scan on
Discovery started
[CHG] Controller B8:27:EB:XX:XX:XX Discovering: yes
[NEW] Device FA:A1:63:XX:XX:XX Desk 7372
[NEW] Device 71:66:5F:XX:XX:XX 71-66-5F-XX-XX-XX
[NEW] Device 5F:DD:10:XX:XX:XX 5F-DD-10-XX-XX-XX
[NEW] Device 68:D9:74:XX:XX:XX 68-D9-74-XX-XX-XX
[NEW] Device 44:B9:01:XX:XX:XX 44-B9-01-XX-XX-XX
[NEW] Device 5D:58:CF:XX:XX:XX 5D-58-CF-XX-XX-XX
[NEW] Device 3C:85:15:XX:XX:XX 3C-85-15-XX-XX-XX
[NEW] Device 39:EA:4A:XX:XX:XX 39-EA-4A-XX-XX-XX
[NEW] Device 68:43:7A:XX:XX:XX 68-43-7A-XX-XX-XX
[NEW] Device 3A:DB:B8:XX:XX:XX 3A-DB-B8-XX-XX-XX
[NEW] Device 40:6F:47:XX:XX:XX 40-6F-47-XX-XX-XX
[NEW] Device 67:8C:1C:XX:XX:XX 67-8C-1C-XX-XX-XX
[CHG] Device 39:EA:4A:XX:XX:XX ManufacturerData Key: 0x004c
[CHG] Device 39:EA:4A:XX:XX:XX ManufacturerData Value:
  09 06 03 e1 c0 a8 0a dc                          ........
[CHG] Device 5F:DD:10:XX:XX:XX RSSI: -31
[CHG] Device 68:43:7A:XX:XX:XX RSSI: -78
[CHG] Device 40:6F:47:XX:XX:XX RSSI: -82
[bluetooth]#

We need to grab the MAC address of the desk controller, in this case it’s the first item on the list named “Desk 7372” with MAC address FA:A1:63:XX:XX:XX (yes, call me paranoid, but I’m not showing it to you).

Tip

If you don’t see device name to identify it, you may need to lookup its MAC address via other means. Use any other system that can connect to desk controller via Bluetooth and display its MAC address, for example a smartphone running Android. I had that problem myself initially, but after couple tries it went away and bluetoothctl started showing device names. Why? I have no idea. It’s Bluetooth!

We are ready to initiate pairing, but before doing that, let’s disable scanning. It’s noisy and we don’t need it anymore:

[bluetooth]# scan off
[...]
[CHG] Controller B8:27:EB:XX:XX:XX Discovering: no
Discovery stopped
[...]
[bluetooth]#

Now make sure the desk controller is still in pairing mode (with blue LED flashing), then initiate pairing with:

[bluetooth]# pair FA:A1:63:XX:XX:XX
Attempting to pair with FA:A1:63:XX:XX:XX
[CHG] Device FA:A1:63:XX:XX:XX Connected: yes
[...]
[bluetooth]#

And trust it for future connections. Note that bluetoothctl changes the prompt to device name after connecting:

[Desk 7372]# trust FA:A1:63:XX:XX:XX
[CHG] Device FA:A1:63:XX:XX:XX Trusted: yes
Changing FA:A1:63:XX:XX:XX trust succeeded
[Desk 7372]#

Now let’s double check that the device is paired and trusted…

[Desk 7372]# info FA:A1:63:XX:XX:XX
Device FA:A1:63:XX:XX:XX (random)
        Name: Desk 7372
        Alias: Desk 7372
        Paired: yes
        Trusted: yes
        Blocked: no
        Connected: yes
        LegacyPairing: no
        UUID: Generic Access Profile    (00001800-0000-1000-8000-00805f9b34fb)
        UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
        UUID: Vendor specific           (99fa0001-338a-1024-8a49-009c0215f78a)
        UUID: Vendor specific           (99fa0010-338a-1024-8a49-009c0215f78a)
        UUID: Vendor specific           (99fa0020-338a-1024-8a49-009c0215f78a)
        UUID: Vendor specific           (99fa0030-338a-1024-8a49-009c0215f78a)
[Desk 7372]#

…and looks like it’s also connected, which is actually not what we want right now. idasen-controller script will try to initiate connection on its own and will simply fail if the device is already connected. So, let’s disconnect with:

[Desk 7372]# disconnect FA:A1:63:XX:XX:XX
Attempting to disconnect from FA:A1:63:XX:XX:XX
[CHG] Device FA:A1:63:XX:XX:XX ServicesResolved: no
Successful disconnected
[CHG] Device FA:A1:63:XX:XX:XX Connected: no
[bluetooth]#

Great! We can move on.

Setup idasen-controller script

First, we need to install pip3 utility with:

sudo apt install python3-pip

Now we can install the script:

pip3 install idasen-controller

Warning

The command above will install idasen-controller under your home directory: /home/$USER/.local/bin/idasen-controller
This may not be desired if you plan to execute it later under a different user, like a service account. This is exactly what I ended up doing in my future post related to this project.

To install idasen-controller for all users you should run:

sudo -H pip3 install idasen-controller

This will install it in /usr/local/bin/idasen-controller
AFAIK there is no global config file and the script looks for it in home directory by default, although that can be changed by executing it with --config PATH.

We also need to setup the config file. Here’s a one liner using nano:

mkdir -p ~/.config/idasen-controller && nano ~/.config/idasen-controller/config.yaml

Now paste the config. Remember to change the MAC address. You should not need to change other values (at least not on Raspberry Pi). Favourites for sit and stand positions can be changed later too:

mac_address: FA:A1:63:XX:XX:XX
scan_timeout: 5
connection_timeout: 10
movement_timeout: 30
adapter_name: hci0
server_address: "127.0.0.1"
server_port: 9123
favourites:
  sit: 680
  stand: 1073

Press CTRL + O to save it, then CTRL + X to exit nano.

Now let’s see if the script can communicate with desk controller. Run idasen-controller and you should see current height in the output:

$ idasen-controller
Connected FA:A1:63:XX:XX:XX
Height:  680mm
Disconnected

You can move the desk now to any desired height with:

$ idasen-controller --move-to 700
Connected FA:A1:63:XX:XX:XX
Height:  680mm
Moving to height: 700
Height:  684mm Speed: 26mm/s
Height:  700mm Speed: 52mm/s
Height:  700mm Speed:  0mm/s
Final height:  700mm (Target:  700mm)
Disconnected

There is a slight delay of 3-4 seconds, which is a downside of having to connect and disconnect each time a command is issued. But! At least we no longer have to hold any buttons. We can work around the delay as well. More on that later.

I have been testing this for few days now and I’m yet to experience any connectivity issues (certainly unavoidable with Bluetooth!). So far it’s not bad.

Here are other useful commands:

CommandDescription
idasen-controllerYou know this one already. It prints current height.
idasen-controller --watchContinuously outputs height as it changes.
idasen-controller --move-to sitMoves the desk to height saved as “sit” from config file.
idasen-controller --move-to standMoves to “stand” height from config file.

Rise!