Ikea Bekant table control over MQTT with Megadesk and ESP32
Ever since I own an Ikea Bekant table with an electric motor I wanted to automate it. Now, after many years, I was able to finish this project.
At the beginning of the idea I thought I can just add a relay to move the table up or down, but soon after opening the case where the buttons are I figured out that there is a microprocessor controlling the table. I then added some cables to the buttons and a distance sensor to a Raspberry Pi and tried to solve it that way, but that didn't really work out, and the project went on-hold.
Along came Megadesk - an Open Source custom controller which replaces the original controller. At first, it "just" had memory positions, but later serial control was added. With an ESP32 attached to this serial interface, my Ikea table is now fully IoT ready, connected to my MQTT broker at home.
How to install Megadesk is already well documented on the linked GitHub page. To upgrade the firmware to the latest one, I ordered a Sparkfun Pocket AVR Programmer and flashed the serial-enabled version v2021.09 (v2021.09-serial.hex) to Megadesk.
In order to successfully upgrade, I downloaded
ATTinyCore directly in the Arduino IDE and installed
avrdude from the Arch Linux community repo.
The commands I used for flashing are as follows (I found them in flash.bat, which obviously doesn't work on Linux):
avrdude -C /home/tobru/.arduino15/packages/ATTinyCore/hardware/avr/1.5.2/avrdude.conf -c usbtiny -p t841 -U lfuse:w:0xe2:m avrdude -C /home/tobru/.arduino15/packages/ATTinyCore/hardware/avr/1.5.2/avrdude.conf -c usbtiny -p t841 -U hfuse:w:0xd6:m avrdude -C /home/tobru/.arduino15/packages/ATTinyCore/hardware/avr/1.5.2/avrdude.conf -c usbtiny -p t841 -U efuse:w:0xfe:m avrdude -C /home/tobru/.arduino15/packages/ATTinyCore/hardware/avr/1.5.2/avrdude.conf -v -pattiny841 -cusbtiny -Uflash:w:v2021.09-serial.hex:i
The connection between the programmer and Megadesk is straight-forward: I just connected the pins which have the same name, as described in the DYI page.
The connection from Megadesk to an ESP32 microcontroller (I'm using the Wemos ESP32MiniKit) looks like that:
MISO -> RX SCK -> TX GND -> GND
Programming the ESP32
As I'm a lazy guy, I'm using ESPHome to configure and flash the ESP32. It just needs some YAML:
esphome: name: megadesk comment: Megadesk IKEA Bekant Controller platform: ESP32 board: wemos_d1_mini32 uart: id: uart_bus baud_rate: 115200 rx_pin: 16 tx_pin: 17 debug: direction: RX dummy_receiver: false after: delimiter: "\n" sequence: - lambda: UARTDebug::log_string(direction, bytes); switch: - platform: uart name: "Desk position up" data: '<L0,3.' - platform: uart name: "Desk position down" data: '<L0,2.' - platform: uart name: "Get desk position" data: '<C0,0.' - platform: uart name: "Go up a bit" data: '<+500..'
Of course if you want it to connect to your Wifi and your MQTT broker, you have to add that accordingly. The ESPHome documentation helps.
With this configuration, I can now move my desk to the stored position 3 by simply publishing a message on MQTT:
mosquitto_pub -t "megadesk/switch/desk_position_up/command" -h mqtt.example.com -m "ON"
And as ESPHome works perfectly fine with Home Assistant, integration there just works.
The serial commands are only documented in a GitHub comment, that's why I'm replicating them here:
After the marker byte '<', there's the Command byte, then two fields of ascii integer digits. Terminate each field with any non-digit character eg !,./ or a line-break. Missing digits are interpreted as a 0 so <L.. is valid and passes two 0s to the L command. First field (position) can be any number up to a maximum of 65535, the second field (slot) has a maximum of 255.
data start (first byte) char meaning ----------------- < start Rx Marker command (second byte) cmd meaning ----------------- + increase - decrease = absolute C Ask for current location S Save location to (UpButton) EEPROM s Save location to Downbutton EEPROM L Load (Upbutton) location from EEPROM and move l load Downbutton location from EEPROM and move W Write arbitrary data to EEPROM R Read arbitrary data from EEPROM T play tone position (third/fourth bytes or 1st digit field. max 65535) cmd meaning ----------------- +- relative to current position =SsW absolute position T tone frequency CRLl (ignore) push_addr (fifth byte or 2nd digit field. max 255) cmd meaning ----------------- SLlWwR EEPROM pushCount/slot T tone duration/4 ms. (250 == 1s) +-=C (ignore) Examples: <W3000,3. # writes location 3 with height 3000. <T3000,255. # plays a 3000Hz tone for 1sec <C0.0. # reports current height <+300.. # nudge desk up by 300 <L,5. # recall position from slot 2 <l,5. # recall position from down-button slot 2 <R.0/ # read eeprom slot 0