anetczuk/LinakDeskApp

Bluetooth command failed (code: 1, error: Invalid handle)

HermannBjorgvin opened this issue Β· 30 comments

Glad to submit the first issue in this repository. Very nice work, this application looks great.

I am getting an error of some kind when I try to connect to my IKEA Linak powered standing desk.

Here is a link to the desk.
https://www.ikea.com/gb/en/p/idasen-desk-sit-stand-black-dark-grey-s89280993/

If this desk isn't supported I'm not here to chase you down to make you support the IKEA desks but could you maybe share some insights into how you managed to create this application? I'm not a Python programmer myself so I can't help too much with coding.

I tried asking Linak if they had some documentation but they responded by saying that was proprietary information. Do you have any advice for someone who hasn't programmed against a bluetooth interface before on how to reverse engineer and figure out how to connect to a Linak desk?

Bluetooth command failed (code: 1, error: Invalid handle) seems to be the important bit where it fails.

linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:292] Got exception from bluepy while making a request: Bluetooth command failed (code: 1, error: Invalid handle)
linak_dpg_bt.connection:wrapper [connection.py:39] bluetooth exception occurred: <class 'bluepy.btle.BTLEGattError'> Bluetooth command failed (code: 1, error: Invalid handle)
linak_dpg_bt.connection.BTLEConnection:disconnect [connection.py:118] disconnecting

Here is the full log

2020-02-19 15:19:11,935 DEBUG    MainThread __main__:main [main.py:108] Starting the application
2020-02-19 15:19:11,935 DEBUG    MainThread __main__:main [main.py:109] Logger log file: /home/hermann/Programs/LinakDeskApp/log.txt
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-root'
2020-02-19 15:19:11,984 DEBUG    MainThread linakdeskapp.gui.suspenddetector.QSuspendTimer:start [suspenddetector.py:44] starting suspension detector
2020-02-19 15:19:11,985 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:setIconTheme [main_window.py:102] setting tray theme: <TrayIconTheme.WHITE: ('office-chair-gray.png', 'office-chair-white.png', 'office-chair-red.png')>
2020-02-19 15:19:11,989 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:loadSettings [main_window.py:142] loading app state from /root/.config/arnet/LinakDeskApp.ini
2020-02-19 15:19:11,990 DEBUG    MainThread linakdeskapp.gui.app_settings_widget.AppSettingsWidget:_toggleAutoReconnectTime [app_settings_widget.py:182] setting auto reconnect timer to 60
2020-02-19 15:19:11,990 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_tryReconnectOnStartup [main_window.py:98] trying reconnect on startup
2020-02-19 15:19:11,990 DEBUG    MainThread linakdeskapp.bt_device_connector.BTDeviceConnector:_changeConnectionStatus [bt_device_connector.py:150] changing connection state to ConnectionState.CONN_IN_PROGRESS

2020-02-19 15:19:12,20  DEBUG    Connect-1 linakdeskapp.bt_device_connector.ThreadWorker:run [bt_device_connector.py:287] Worker start
2020-02-19 15:19:12,23  DEBUG    Connect-1 linak_dpg_bt.connection.BTLEConnection:__init__ [connection.py:62] Constructed BTLEConnection object: <linak_dpg_bt.connection.BTLEConnection object at 0x7fb9c3045a60>
2020-02-19 15:19:12,23  DEBUG    Connect-1 linak_dpg_bt.linak_device.LinakDesk:__init__ [linak_device.py:109] Constructed LinakDesk object: <linak_dpg_bt.linak_device.LinakDesk object at 0x7fb9c30457c0>
2020-02-19 15:19:12,23  DEBUG    Connect-1 linak_dpg_bt.linak_device.LinakDesk:_connect [linak_device.py:347] Initializing the device
2020-02-19 15:19:12,23  DEBUG    Connect-1 linak_dpg_bt.connection.BTLEConnection:connect [connection.py:95] Trying to connect to 
2020-02-19 15:19:12,23  ERROR    Connect-1 linak_dpg_bt.linak_device.LinakDesk:initialize [linak_device.py:343] Initialization failed: <class 'ValueError'> Expected MAC address, got ''
2020-02-19 15:19:12,23  DEBUG    Connect-1 linakdeskapp.bt_device_connector.BTDeviceConnector:_initializeDevice [bt_device_connector.py:119] Could not connect to to device: <linak_dpg_bt.linak_device.LinakDesk object at 0x7fb9c30457c0>
2020-02-19 15:19:12,23  DEBUG    Connect-1 linakdeskapp.bt_device_connector.BTDeviceConnector:_changeConnectionStatus [bt_device_connector.py:150] changing connection state to ConnectionState.DISCONNECTED
2020-02-19 15:19:12,24  DEBUG    Connect-1 linakdeskapp.bt_device_connector.ThreadWorker:run [bt_device_connector.py:289] Worker complete

// Scan for desk

2020-02-19 15:19:16,45  DEBUG    MainThread linakdeskapp.bt_device_connector.BTDeviceConnector:scanDevices [bt_device_connector.py:74] Scanning bluetooth devices
2020-02-19 15:19:18,277 DEBUG    MainThread linak_dpg_bt.linak_device.LinakDesk:__del__ [linak_device.py:112] Deleting LinakDesk object: <linak_dpg_bt.linak_device.LinakDesk object at 0x7fb9c30457c0>
2020-02-19 15:19:18,277 DEBUG    MainThread linak_dpg_bt.connection.BTLEConnection:__del__ [connection.py:87] Deleting BTLEConnection object: <linak_dpg_bt.connection.BTLEConnection object at 0x7fb9c3045a60>
2020-02-19 15:19:18,277 DEBUG    MainThread linak_dpg_bt.connection.BTLEConnection:disconnect [connection.py:118] disconnecting
2020-02-19 15:19:26,298 DEBUG    MainThread linakdeskapp.bt_device_connector.BTDeviceConnector:scanDevices [bt_device_connector.py:90] Scanning finished
2020-02-19 15:19:26,300 DEBUG    MainThread linakdeskapp.gui.suspenddetector.QSuspendTimer:checkResumed [suspenddetector.py:62] resumed from suspend / hibernation after 10.512005[s]
2020-02-19 15:19:26,316 DEBUG    MainThread linakdeskapp.bt_device_connector.BTDeviceConnector:scanDevices [bt_device_connector.py:74] Scanning bluetooth devices
2020-02-19 15:19:36,458 DEBUG    MainThread linakdeskapp.bt_device_connector.BTDeviceConnector:scanDevices [bt_device_connector.py:90] Scanning finished
2020-02-19 15:19:36,458 DEBUG    MainThread linakdeskapp.gui.suspenddetector.QSuspendTimer:checkResumed [suspenddetector.py:62] resumed from suspend / hibernation after 10.158263[s]
2020-02-19 15:19:40,27  DEBUG    MainThread linakdeskapp.bt_device_connector.BTDeviceConnector:scanDevices [bt_device_connector.py:74] Scanning bluetooth devices
2020-02-19 15:19:50,281 DEBUG    MainThread linakdeskapp.bt_device_connector.BTDeviceConnector:scanDevices [bt_device_connector.py:90] Scanning finished
2020-02-19 15:19:50,283 DEBUG    MainThread linakdeskapp.gui.suspenddetector.QSuspendTimer:checkResumed [suspenddetector.py:62] resumed from suspend / hibernation after 10.97479[s]
2020-02-19 15:19:54,537 DEBUG    MainThread linakdeskapp.bt_device_connector.BTDeviceConnector:_changeConnectionStatus [bt_device_connector.py:150] changing connection state to ConnectionState.CONN_IN_PROGRESS

// Connect to my IKEA desk, failed connection

2020-02-19 15:19:54,539 DEBUG    Connect-2 linakdeskapp.bt_device_connector.ThreadWorker:run [bt_device_connector.py:287] Worker start
2020-02-19 15:19:54,539 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:__init__ [connection.py:62] Constructed BTLEConnection object: <linak_dpg_bt.connection.BTLEConnection object at 0x7fb9c3045ca0>
2020-02-19 15:19:54,540 DEBUG    Connect-2 linak_dpg_bt.linak_device.LinakDesk:__init__ [linak_device.py:109] Constructed LinakDesk object: <linak_dpg_bt.linak_device.LinakDesk object at 0x7fb9c3045d00>
2020-02-19 15:19:54,540 DEBUG    Connect-2 linak_dpg_bt.linak_device.LinakDesk:_connect [linak_device.py:347] Initializing the device
2020-02-19 15:19:54,540 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:connect [connection.py:95] Trying to connect to f1:0c:41:3a:4b:20
2020-02-19 15:19:54,786 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:connect [connection.py:112] Connected to f1:0c:41:3a:4b:20
2020-02-19 15:19:55,322 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.HEIGHT_SPEED[99FA0021-338A-1024-8A49-009C0215F78A, 0x1d]
2020-02-19 15:19:55,323 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.HEIGHT_SPEED[99FA0021-338A-1024-8A49-009C0215F78A, 0x1d] w_resp=False
2020-02-19 15:19:55,324 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.TWO[99FA0022-338A-1024-8A49-009C0215F78A, 0x20]
2020-02-19 15:19:55,324 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.TWO[99FA0022-338A-1024-8A49-009C0215F78A, 0x20] w_resp=False
2020-02-19 15:19:55,325 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.THREE[99FA0023-338A-1024-8A49-009C0215F78A, 0x23]
2020-02-19 15:19:55,325 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.THREE[99FA0023-338A-1024-8A49-009C0215F78A, 0x23] w_resp=False
2020-02-19 15:19:55,326 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.FOUR[99FA0024-338A-1024-8A49-009C0215F78A, 0x26]
2020-02-19 15:19:55,326 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.FOUR[99FA0024-338A-1024-8A49-009C0215F78A, 0x26] w_resp=False
2020-02-19 15:19:55,326 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.FIVE[99FA0025-338A-1024-8A49-009C0215F78A, 0x29]
2020-02-19 15:19:55,327 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.FIVE[99FA0025-338A-1024-8A49-009C0215F78A, 0x29] w_resp=False
2020-02-19 15:19:55,327 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.SIX[99FA0026-338A-1024-8A49-009C0215F78A, 0x2c]
2020-02-19 15:19:55,327 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.SIX[99FA0026-338A-1024-8A49-009C0215F78A, 0x2c] w_resp=False
2020-02-19 15:19:55,328 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.SEVEN[99FA0027-338A-1024-8A49-009C0215F78A, 0x2f]
2020-02-19 15:19:55,328 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.SEVEN[99FA0027-338A-1024-8A49-009C0215F78A, 0x2f] w_resp=False
2020-02-19 15:19:55,329 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.EIGHT[99FA0028-338A-1024-8A49-009C0215F78A, 0x32]
2020-02-19 15:19:55,329 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.EIGHT[99FA0028-338A-1024-8A49-009C0215F78A, 0x32] w_resp=False
2020-02-19 15:19:55,330 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:284] Reading char: Characteristic.MASK[99FA0029-338A-1024-8A49-009C0215F78A, 0x35]
2020-02-19 15:19:55,516 ERROR    Connect-2 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:292] Got exception from bluepy while making a request: Bluetooth command failed (code: 1, error: Invalid handle)
2020-02-19 15:19:55,517 ERROR    Connect-2 linak_dpg_bt.connection:wrapper [connection.py:39] bluetooth exception occurred: <class 'bluepy.btle.BTLEGattError'> Bluetooth command failed (code: 1, error: Invalid handle)
2020-02-19 15:19:55,517 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:disconnect [connection.py:118] disconnecting
2020-02-19 15:19:55,521 ERROR    Connect-2 linak_dpg_bt.linak_device.LinakDesk:initialize [linak_device.py:343] Initialization failed: <class 'bluepy.btle.BTLEGattError'> Bluetooth command failed (code: 1, error: Invalid handle)
2020-02-19 15:19:55,522 DEBUG    Connect-2 linakdeskapp.bt_device_connector.BTDeviceConnector:_initializeDevice [bt_device_connector.py:119] Could not connect to to device: <linak_dpg_bt.linak_device.LinakDesk object at 0x7fb9c3045d00>
2020-02-19 15:19:55,522 DEBUG    Connect-2 linakdeskapp.bt_device_connector.BTDeviceConnector:_changeConnectionStatus [bt_device_connector.py:150] changing connection state to ConnectionState.DISCONNECTED
2020-02-19 15:19:55,522 DEBUG    Connect-2 linakdeskapp.bt_device_connector.ThreadWorker:run [bt_device_connector.py:289] Worker complete

Thanks for the issue.

IKEA website does not provide technical details about hardware You have. First of all You can check model number of Your device. It should be written on label of controller.
Logs says that Bluetooth was able to connect to the device, but problem is that there is no required attribute. Application has problem reading following BT attribute: 99FA0029-338A-1024-8A49-009C0215F78A.
You can install "GATTBrowser" or similar application on Your Android device (phone or tablet) investigate device's attributes.
In repo there is also script listing all characteristics of BT device. You will find it in
test/gatttool/020_list_services.ssh. Other scripts might be helpful too.

For purpose of this application I developed a tool (https://github.com/anetczuk/BluetoothGattMitm). You can use it to reverse engineer protocol between Your device and Linak Android application.

Thanks for the response.

The controller is labeled: DPG1I002-00 same family as the DPG products but probably an IKEA variant, it looks similar to a DPG except it is light gray and only has the bluetooht pairing button. In the app you can switch between inches/cm units and save 3 presets, as well as changing the desk name.

I installed GATT browser and found the characteristic that notifies when the height is changed, I will research this more in my spare time soon.

Your MITM tool looks great, I will try to reverse engineer and document the characteristics of the IKEA DPG variant probably this weekend, fun weekend ahead tinkering with a desk.

Check in GATT Browser if there is the Mask characteristic (99FA0029-338A-1024-8A49-009C0215F78A).
In application it only serves to detect type of device (e.g. Desk, LegRest), so for testing purpose You could comment out or hardcode part that is responsible for reading this characteristic.

@anetczuk thanks for that tip, I'll send you that information when I get home from work. I'm going to compare and check the characteristics in "linak_bt_desk/linak_dpg_bt/linak_service.py" as well, of course if the characteristics are not the same it would of course just return a lot of errors.

Also going to send a dump of the characteristics. I've also tried listing the GATT characteristics in Bluez via the bluetoothctl command line tool, will add that to the issue as well.

I also tried sending Linak one more request to see if they could provide documentation on the GATT characteristics but I doubt they will help since they view that as proprietary information.

I've just tried to use your code on the exact same desk from IKEA.

2020-02-28 18:30:22,602 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:__init__ [connection.py:62] Constructed BTLEConnection object: <linak_dpg_bt.connection.BTLEConnection object at 0x7f941c9237d0>
2020-02-28 18:30:22,602 DEBUG    Connect-11 linak_dpg_bt.linak_device.LinakDesk:__init__ [linak_device.py:109] Constructed LinakDesk object: <linak_dpg_bt.linak_device.LinakDesk object at 0x7f941c923b10>
2020-02-28 18:30:22,602 DEBUG    Connect-11 linak_dpg_bt.linak_device.LinakDesk:_connect [linak_device.py:347] Initializing the device
2020-02-28 18:30:22,602 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:connect [connection.py:95] Trying to connect to cf:6b:d8:7b:ae:88
2020-02-28 18:30:22,961 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:connect [connection.py:112] Connected to cf:6b:d8:7b:ae:88
2020-02-28 18:30:23,456 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.HEIGHT_SPEED[99FA0021-338A-1024-8A49-009C0215F78A, 0x1d]
2020-02-28 18:30:23,456 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.HEIGHT_SPEED[99FA0021-338A-1024-8A49-009C0215F78A, 0x1d] w_resp=False
2020-02-28 18:30:23,457 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.TWO[99FA0022-338A-1024-8A49-009C0215F78A, 0x20]
2020-02-28 18:30:23,457 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.TWO[99FA0022-338A-1024-8A49-009C0215F78A, 0x20] w_resp=False
2020-02-28 18:30:23,457 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.THREE[99FA0023-338A-1024-8A49-009C0215F78A, 0x23]
2020-02-28 18:30:23,457 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.THREE[99FA0023-338A-1024-8A49-009C0215F78A, 0x23] w_resp=False
2020-02-28 18:30:23,458 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.FOUR[99FA0024-338A-1024-8A49-009C0215F78A, 0x26]
2020-02-28 18:30:23,458 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.FOUR[99FA0024-338A-1024-8A49-009C0215F78A, 0x26] w_resp=False
2020-02-28 18:30:23,458 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.FIVE[99FA0025-338A-1024-8A49-009C0215F78A, 0x29]
2020-02-28 18:30:23,458 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.FIVE[99FA0025-338A-1024-8A49-009C0215F78A, 0x29] w_resp=False
2020-02-28 18:30:23,459 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.SIX[99FA0026-338A-1024-8A49-009C0215F78A, 0x2c]
2020-02-28 18:30:23,459 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.SIX[99FA0026-338A-1024-8A49-009C0215F78A, 0x2c] w_resp=False
2020-02-28 18:30:23,459 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.SEVEN[99FA0027-338A-1024-8A49-009C0215F78A, 0x2f]
2020-02-28 18:30:23,459 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.SEVEN[99FA0027-338A-1024-8A49-009C0215F78A, 0x2f] w_resp=False
2020-02-28 18:30:23,460 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.EIGHT[99FA0028-338A-1024-8A49-009C0215F78A, 0x32]
2020-02-28 18:30:23,460 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.EIGHT[99FA0028-338A-1024-8A49-009C0215F78A, 0x32] w_resp=False
2020-02-28 18:30:23,460 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:284] Reading char: Characteristic.MASK[99FA0029-338A-1024-8A49-009C0215F78A, 0x35]
2020-02-28 18:30:23,635 ERROR    Connect-11 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:292] Got exception from bluepy while making a request: Bluetooth command failed (code: 1, error: Invalid handle)
2020-02-28 18:30:23,636 ERROR    Connect-11 linak_dpg_bt.connection:wrapper [connection.py:39] bluetooth exception occurred: <class 'bluepy.btle.BTLEGattError'> Bluetooth command failed (code: 1, error: Invalid handle)
2020-02-28 18:30:23,636 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:disconnect [connection.py:118] disconnecting
2020-02-28 18:30:23,637 ERROR    Connect-11 linak_dpg_bt.linak_device.LinakDesk:initialize [linak_device.py:343] Initialization failed: <class 'bluepy.btle.BTLEGattError'> Bluetooth command failed (code: 1, error: Invalid handle)
2020-02-28 18:30:23,637 DEBUG    Connect-11 linakdeskapp.bt_device_connector.BTDeviceConnector:_initializeDevice [bt_device_connector.py:119] Could not connect to to device: <linak_dpg_bt.linak_device.LinakDesk object at 0x7f941c923b10>
2020-02-28 18:30:23,637 DEBUG    Connect-11 linakdeskapp.bt_device_connector.BTDeviceConnector:_changeConnectionStatus [bt_device_connector.py:150] changing connection state to ConnectionState.DISCONNECTED
2020-02-28 18:30:23,638 DEBUG    Connect-11 linakdeskapp.bt_device_connector.ThreadWorker:run [bt_device_connector.py:290] Worker complete

output from gatttool:

2020-02-28 18:30:22,602 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:__init__ [connection.py:62] Constructed BTLEConnection object: <linak_dpg_bt.connection.BTLEConnection object at 0x7f941c9237d0>
2020-02-28 18:30:22,602 DEBUG    Connect-11 linak_dpg_bt.linak_device.LinakDesk:__init__ [linak_device.py:109] Constructed LinakDesk object: <linak_dpg_bt.linak_device.LinakDesk object at 0x7f941c923b10>
2020-02-28 18:30:22,602 DEBUG    Connect-11 linak_dpg_bt.linak_device.LinakDesk:_connect [linak_device.py:347] Initializing the device
2020-02-28 18:30:22,602 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:connect [connection.py:95] Trying to connect to cf:6b:d8:7b:ae:88
2020-02-28 18:30:22,961 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:connect [connection.py:112] Connected to cf:6b:d8:7b:ae:88
2020-02-28 18:30:23,456 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.HEIGHT_SPEED[99FA0021-338A-1024-8A49-009C0215F78A, 0x1d]
2020-02-28 18:30:23,456 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.HEIGHT_SPEED[99FA0021-338A-1024-8A49-009C0215F78A, 0x1d] w_resp=False
2020-02-28 18:30:23,457 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.TWO[99FA0022-338A-1024-8A49-009C0215F78A, 0x20]
2020-02-28 18:30:23,457 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.TWO[99FA0022-338A-1024-8A49-009C0215F78A, 0x20] w_resp=False
2020-02-28 18:30:23,457 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.THREE[99FA0023-338A-1024-8A49-009C0215F78A, 0x23]
2020-02-28 18:30:23,457 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.THREE[99FA0023-338A-1024-8A49-009C0215F78A, 0x23] w_resp=False
2020-02-28 18:30:23,458 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.FOUR[99FA0024-338A-1024-8A49-009C0215F78A, 0x26]
2020-02-28 18:30:23,458 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.FOUR[99FA0024-338A-1024-8A49-009C0215F78A, 0x26] w_resp=False
2020-02-28 18:30:23,458 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.FIVE[99FA0025-338A-1024-8A49-009C0215F78A, 0x29]
2020-02-28 18:30:23,458 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.FIVE[99FA0025-338A-1024-8A49-009C0215F78A, 0x29] w_resp=False
2020-02-28 18:30:23,459 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.SIX[99FA0026-338A-1024-8A49-009C0215F78A, 0x2c]
2020-02-28 18:30:23,459 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.SIX[99FA0026-338A-1024-8A49-009C0215F78A, 0x2c] w_resp=False
2020-02-28 18:30:23,459 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.SEVEN[99FA0027-338A-1024-8A49-009C0215F78A, 0x2f]
2020-02-28 18:30:23,459 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.SEVEN[99FA0027-338A-1024-8A49-009C0215F78A, 0x2f] w_resp=False
2020-02-28 18:30:23,460 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.EIGHT[99FA0028-338A-1024-8A49-009C0215F78A, 0x32]
2020-02-28 18:30:23,460 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.EIGHT[99FA0028-338A-1024-8A49-009C0215F78A, 0x32] w_resp=False
2020-02-28 18:30:23,460 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:284] Reading char: Characteristic.MASK[99FA0029-338A-1024-8A49-009C0215F78A, 0x35]
2020-02-28 18:30:23,635 ERROR    Connect-11 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:292] Got exception from bluepy while making a request: Bluetooth command failed (code: 1, error: Invalid handle)
2020-02-28 18:30:23,636 ERROR    Connect-11 linak_dpg_bt.connection:wrapper [connection.py:39] bluetooth exception occurred: <class 'bluepy.btle.BTLEGattError'> Bluetooth command failed (code: 1, error: Invalid handle)
2020-02-28 18:30:23,636 DEBUG    Connect-11 linak_dpg_bt.connection.BTLEConnection:disconnect [connection.py:118] disconnecting
2020-02-28 18:30:23,637 ERROR    Connect-11 linak_dpg_bt.linak_device.LinakDesk:initialize [linak_device.py:343] Initialization failed: <class 'bluepy.btle.BTLEGattError'> Bluetooth command failed (code: 1, error: Invalid handle)
2020-02-28 18:30:23,637 DEBUG    Connect-11 linakdeskapp.bt_device_connector.BTDeviceConnector:_initializeDevice [bt_device_connector.py:119] Could not connect to to device: <linak_dpg_bt.linak_device.LinakDesk object at 0x7f941c923b10>
2020-02-28 18:30:23,637 DEBUG    Connect-11 linakdeskapp.bt_device_connector.BTDeviceConnector:_changeConnectionStatus [bt_device_connector.py:150] changing connection state to ConnectionState.DISCONNECTED
2020-02-28 18:30:23,638 DEBUG    Connect-11 linakdeskapp.bt_device_connector.ThreadWorker:run [bt_device_connector.py:290] Worker complete

so the UID exists in the characteristics:
handle = 0x001c, char properties = 0x02, char value handle = 0x001d, uuid = 99fa0029-338a-1024-8a49-009c0215f78a

I'll try the MITM tool tomorrow and play with the suggested edits.
It would be great if we can make this work.

There is no gatttool output -- Your gatttool output shows application log.
Please verify if You have handle (0x35) associated with the characteristic. Gatttool shoul present following log:
char value handle = 0x0035, uuid = 99fa0029-338a-1024-8a49-009c0215f78a in characteristics section or
handle = 0x0035, uuid = 99fa0029-338a-1024-8a49-009c0215f78a in descriptors section.

@anetczuk I found out for my version of Bluez gatttool has bee depreciated (yay).

I found a way to list the gatt characteristics by using the gatt menu in bluetoothctl, here is the log for my IKEA desk. I also tried once more to email Linak but they consider the gatt attributes to be proprietary information.

It looks like 99fa0029-338a-1024-8a49-009c0215f78a has the handle: 0x983e for this desk.

Output from list-attributes in bluetoothctl

[bluetooth]# connect F1:0C:41:3A:4B:20
Attempting to connect to F1:0C:41:3A:4B:20
[CHG] Device F1:0C:41:3A:4B:20 RSSI: -53
[CHG] Device F1:0C:41:3A:4B:20 Connected: yes
Connection successful
[NEW] Primary Service (Handle 0x983e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service000a
	00001801-0000-1000-8000-00805f9b34fb
	Generic Attribute Profile
[NEW] Characteristic (Handle 0x983e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service000a/char000b
	00002a05-0000-1000-8000-00805f9b34fb
	Service Changed
[NEW] Descriptor (Handle 0x0f54)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service000a/char000b/desc000d
	00002902-0000-1000-8000-00805f9b34fb
	Client Characteristic Configuration
[NEW] Primary Service (Handle 0x983e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service000e
	99fa0001-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Characteristic (Handle 0x983e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service000e/char000f
	99fa0002-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Characteristic (Handle 0x983e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service000e/char0011
	99fa0003-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Descriptor (Handle 0x4974)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service000e/char0011/desc0013
	00002902-0000-1000-8000-00805f9b34fb
	Client Characteristic Configuration
[NEW] Primary Service (Handle 0x983e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0014
	99fa0010-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Characteristic (Handle 0x983e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0014/char0015
	99fa0011-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Descriptor (Handle 0x52b4)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0014/char0015/desc0017
	00002902-0000-1000-8000-00805f9b34fb
	Client Characteristic Configuration
[NEW] Primary Service (Handle 0x983e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0018
	99fa0020-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Characteristic (Handle 0x983e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0018/char0019
	99fa0021-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Descriptor (Handle 0x62d4)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0018/char0019/desc001b
	00002902-0000-1000-8000-00805f9b34fb
	Client Characteristic Configuration
[NEW] Characteristic (Handle 0x983e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0018/char001c
	99fa0029-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Characteristic (Handle 0x983e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0018/char001e
	99fa002a-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Primary Service (Handle 0x983e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0020
	99fa0030-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Characteristic (Handle 0x983e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0020/char0021
	99fa0031-338a-1024-8a49-009c0215f78a
	Vendor specific

Have You tried reading directly from the handler or changing handler's ID in source code?
Out of curiosity, my desk advertises about 37 entries (Yours 17).

It looks like handler numbers varies from device to device. I made small improvement in linak_bt_desk to use UUID when reading by handler fails. Try if it works.

@anetczuk I pulled the latest from the master branch and pulled the latest from the linak_bt_desk submodule. It looks like it starts failing in this line after it reads the MANUFACTURER characteristic 2020-02-29 23:27:43,850 ERROR Connect-2 linak_dpg_bt.linak_device.LinakDesk:initialize [linak_device.py:343] Initialization failed: <class 'UnicodeDecodeError'> 'utf-8' codec can't decode byte 0x8a in position 0: invalid start byte.

Great progress! There is no longer the same invalid handle error.

If I had to take a blind guess I would maybe guess that the IKEA desks have a limited feature set compared to your desk, the IKEA controller only has the up/down paddle and the bluetooth pairing button, looks like the other Linak controllers have extra features.

2020-02-29 23:27:20,754 DEBUG    MainThread __main__:main [main.py:108] Starting the application
2020-02-29 23:27:20,754 DEBUG    MainThread __main__:main [main.py:109] Logger log file: /home/hermann/Programs/LinakDeskApp/log.txt
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-root'
2020-02-29 23:27:20,805 DEBUG    MainThread linakdeskapp.gui.suspenddetector.QSuspendTimer:start [suspenddetector.py:49] starting suspension detector
2020-02-29 23:27:20,807 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:setIconTheme [main_window.py:102] setting tray theme: <TrayIconTheme.WHITE: ('office-chair-gray.png', 'office-chair-white.png', 'office-chair-red.png')>
2020-02-29 23:27:20,810 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7ff703dc8b80>
2020-02-29 23:27:20,811 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:loadSettings [main_window.py:145] loading app state from /root/.config/arnet/LinakDeskApp.ini
2020-02-29 23:27:20,811 DEBUG    MainThread linakdeskapp.gui.app_settings_widget.AppSettingsWidget:_toggleAutoReconnectTime [app_settings_widget.py:182] setting auto reconnect timer to 60
2020-02-29 23:27:20,811 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7ff703dc8b80>
2020-02-29 23:27:20,812 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_tryReconnectOnStartup [main_window.py:98] trying reconnect on startup
2020-02-29 23:27:20,812 DEBUG    MainThread linakdeskapp.bt_device_connector.BTDeviceConnector:_changeConnectionStatus [bt_device_connector.py:150] changing connection state to ConnectionState.CONN_IN_PROGRESS
2020-02-29 23:27:20,812 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7ff703dc8b80>
2020-02-29 23:27:20,812 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7ff703dc8b80>
2020-02-29 23:27:20,832 DEBUG    Connect-1 linakdeskapp.bt_device_connector.ThreadWorker:run [bt_device_connector.py:288] Worker start
2020-02-29 23:27:20,833 DEBUG    Connect-1 linak_dpg_bt.connection.BTLEConnection:__init__ [connection.py:62] Constructed BTLEConnection object: <linak_dpg_bt.connection.BTLEConnection object at 0x7ff703dd5a90>
2020-02-29 23:27:20,833 DEBUG    Connect-1 linak_dpg_bt.linak_device.LinakDesk:__init__ [linak_device.py:109] Constructed LinakDesk object: <linak_dpg_bt.linak_device.LinakDesk object at 0x7ff703dd57f0>
2020-02-29 23:27:20,833 DEBUG    Connect-1 linak_dpg_bt.linak_device.LinakDesk:_connect [linak_device.py:347] Initializing the device
2020-02-29 23:27:20,833 DEBUG    Connect-1 linak_dpg_bt.connection.BTLEConnection:connect [connection.py:95] Trying to connect to 
2020-02-29 23:27:20,833 ERROR    Connect-1 linak_dpg_bt.linak_device.LinakDesk:initialize [linak_device.py:343] Initialization failed: <class 'ValueError'> Expected MAC address, got ''
2020-02-29 23:27:20,833 DEBUG    Connect-1 linakdeskapp.bt_device_connector.BTDeviceConnector:_initializeDevice [bt_device_connector.py:119] Could not connect to to device: <linak_dpg_bt.linak_device.LinakDesk object at 0x7ff703dd57f0>
2020-02-29 23:27:20,833 DEBUG    Connect-1 linakdeskapp.bt_device_connector.BTDeviceConnector:_changeConnectionStatus [bt_device_connector.py:150] changing connection state to ConnectionState.DISCONNECTED
2020-02-29 23:27:20,833 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7ff703dc8b80>
2020-02-29 23:27:20,833 DEBUG    Connect-1 linakdeskapp.bt_device_connector.ThreadWorker:run [bt_device_connector.py:290] Worker complete
2020-02-29 23:27:20,834 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7ff703dc8b80>
2020-02-29 23:27:28,787 DEBUG    MainThread linakdeskapp.bt_device_connector.BTDeviceConnector:scanDevices [bt_device_connector.py:74] Scanning bluetooth devices
2020-02-29 23:27:30,126 DEBUG    MainThread linak_dpg_bt.linak_device.LinakDesk:__del__ [linak_device.py:112] Deleting LinakDesk object: <linak_dpg_bt.linak_device.LinakDesk object at 0x7ff703dd57f0>
2020-02-29 23:27:30,127 DEBUG    MainThread linak_dpg_bt.connection.BTLEConnection:__del__ [connection.py:87] Deleting BTLEConnection object: <linak_dpg_bt.connection.BTLEConnection object at 0x7ff703dd5a90>
2020-02-29 23:27:30,128 DEBUG    MainThread linak_dpg_bt.connection.BTLEConnection:disconnect [connection.py:118] disconnecting
2020-02-29 23:27:38,923 DEBUG    MainThread linakdeskapp.bt_device_connector.BTDeviceConnector:scanDevices [bt_device_connector.py:90] Scanning finished
2020-02-29 23:27:38,926 DEBUG    MainThread linakdeskapp.gui.suspenddetector.QSuspendTimer:checkResumed [suspenddetector.py:67] resumed from suspend / hibernation after 11.040349[s]
2020-02-29 23:27:41,221 DEBUG    MainThread linakdeskapp.bt_device_connector.BTDeviceConnector:_changeConnectionStatus [bt_device_connector.py:150] changing connection state to ConnectionState.CONN_IN_PROGRESS
2020-02-29 23:27:41,223 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7ff703dc8b80>
2020-02-29 23:27:41,228 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7ff703dc8b80>
2020-02-29 23:27:41,233 DEBUG    Connect-2 linakdeskapp.bt_device_connector.ThreadWorker:run [bt_device_connector.py:288] Worker start
2020-02-29 23:27:41,234 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:__init__ [connection.py:62] Constructed BTLEConnection object: <linak_dpg_bt.connection.BTLEConnection object at 0x7ff703dd5d60>
2020-02-29 23:27:41,234 DEBUG    Connect-2 linak_dpg_bt.linak_device.LinakDesk:__init__ [linak_device.py:109] Constructed LinakDesk object: <linak_dpg_bt.linak_device.LinakDesk object at 0x7ff703dd55e0>
2020-02-29 23:27:41,235 DEBUG    Connect-2 linak_dpg_bt.linak_device.LinakDesk:_connect [linak_device.py:347] Initializing the device
2020-02-29 23:27:41,235 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:connect [connection.py:95] Trying to connect to f1:0c:41:3a:4b:20
2020-02-29 23:27:41,414 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:connect [connection.py:112] Connected to f1:0c:41:3a:4b:20
2020-02-29 23:27:41,950 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.HEIGHT_SPEED[99FA0021-338A-1024-8A49-009C0215F78A, 0x1d]
2020-02-29 23:27:41,951 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.HEIGHT_SPEED[99FA0021-338A-1024-8A49-009C0215F78A, 0x1d] w_resp=False
2020-02-29 23:27:41,952 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.TWO[99FA0022-338A-1024-8A49-009C0215F78A, 0x20]
2020-02-29 23:27:41,952 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.TWO[99FA0022-338A-1024-8A49-009C0215F78A, 0x20] w_resp=False
2020-02-29 23:27:41,954 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.THREE[99FA0023-338A-1024-8A49-009C0215F78A, 0x23]
2020-02-29 23:27:41,954 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.THREE[99FA0023-338A-1024-8A49-009C0215F78A, 0x23] w_resp=False
2020-02-29 23:27:41,955 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.FOUR[99FA0024-338A-1024-8A49-009C0215F78A, 0x26]
2020-02-29 23:27:41,955 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.FOUR[99FA0024-338A-1024-8A49-009C0215F78A, 0x26] w_resp=False
2020-02-29 23:27:41,956 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.FIVE[99FA0025-338A-1024-8A49-009C0215F78A, 0x29]
2020-02-29 23:27:41,957 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.FIVE[99FA0025-338A-1024-8A49-009C0215F78A, 0x29] w_resp=False
2020-02-29 23:27:41,957 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.SIX[99FA0026-338A-1024-8A49-009C0215F78A, 0x2c]
2020-02-29 23:27:41,958 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.SIX[99FA0026-338A-1024-8A49-009C0215F78A, 0x2c] w_resp=False
2020-02-29 23:27:41,959 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.SEVEN[99FA0027-338A-1024-8A49-009C0215F78A, 0x2f]
2020-02-29 23:27:41,959 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.SEVEN[99FA0027-338A-1024-8A49-009C0215F78A, 0x2f] w_resp=False
2020-02-29 23:27:41,959 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.EIGHT[99FA0028-338A-1024-8A49-009C0215F78A, 0x32]
2020-02-29 23:27:41,960 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.EIGHT[99FA0028-338A-1024-8A49-009C0215F78A, 0x32] w_resp=False
2020-02-29 23:27:41,960 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:284] Reading char: Characteristic.MASK[99FA0029-338A-1024-8A49-009C0215F78A, 0x35]
2020-02-29 23:27:42,144 ERROR    Connect-2 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:292] Got exception from bluepy while making a request: Bluetooth command failed (code: 1, error: Invalid handle)
2020-02-29 23:27:42,144 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:297] trying to access characteristic by uuid: 99FA0029-338A-1024-8A49-009C0215F78A
2020-02-29 23:27:43,607 DEBUG    Connect-2 linak_dpg_bt.linak_device.LinakDesk:_connect [linak_device.py:377] Received mask: Mask[ActuatorType.Desk 0x1]
2020-02-29 23:27:43,608 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:284] Reading char: Characteristic.DEVICE_NAME[00002A00-0000-1000-8000-00805F9B34FB, 0x3]
2020-02-29 23:27:43,704 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:289] Got value [0x44 0x65 0x73 0x6B 0x20 0x39 0x32 0x33 0x32]
2020-02-29 23:27:43,704 DEBUG    Connect-2 linak_dpg_bt.linak_device.LinakDesk:_connect [linak_device.py:381] Received name: Desk 9232
2020-02-29 23:27:43,704 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:284] Reading char: Characteristic.MANUFACTURER[00002A29-0000-1000-8000-00805F9B34FB, 0x18]
2020-02-29 23:27:43,850 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:289] Got value [0x8A 0xF7 0x15 0x02 0x9C 0x00 0x49 0x8A 0x24 0x10 0x8A 0x33 0x20 0x00 0xFA 0x99]
2020-02-29 23:27:43,850 ERROR    Connect-2 linak_dpg_bt.linak_device.LinakDesk:initialize [linak_device.py:343] Initialization failed: <class 'UnicodeDecodeError'> 'utf-8' codec can't decode byte 0x8a in position 0: invalid start byte
2020-02-29 23:27:43,850 DEBUG    Connect-2 linakdeskapp.bt_device_connector.BTDeviceConnector:_initializeDevice [bt_device_connector.py:119] Could not connect to to device: <linak_dpg_bt.linak_device.LinakDesk object at 0x7ff703dd55e0>
2020-02-29 23:27:43,851 DEBUG    Connect-2 linakdeskapp.bt_device_connector.BTDeviceConnector:_changeConnectionStatus [bt_device_connector.py:150] changing connection state to ConnectionState.DISCONNECTED
2020-02-29 23:27:43,851 DEBUG    Connect-2 linakdeskapp.bt_device_connector.ThreadWorker:run [bt_device_connector.py:290] Worker complete
2020-02-29 23:27:43,852 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7ff703dc8b80>
2020-02-29 23:27:43,853 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7ff703dc8b80>

Please verify by GATT Browser what is Your handler for characteristic "00002A29-0000-1000-8000-00805F9B34FB", what is content of this characteristic and what characteristic uses handler 0x18.

@anetczuk looked in GATT browser as well as bluetoothcli, the IKEA desk doesn't have that characteristic UUID

Here is the bluetoothctl output with the characteristics that are advertised

[NEW] Primary Service (Handle 0x283e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service000a
	00001801-0000-1000-8000-00805f9b34fb
	Generic Attribute Profile
[NEW] Characteristic (Handle 0x283e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service000a/char000b
	00002a05-0000-1000-8000-00805f9b34fb
	Service Changed
[NEW] Descriptor (Handle 0x4244)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service000a/char000b/desc000d
	00002902-0000-1000-8000-00805f9b34fb
	Client Characteristic Configuration
[NEW] Primary Service (Handle 0x283e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service000e
	99fa0001-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Characteristic (Handle 0x283e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service000e/char000f
	99fa0002-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Characteristic (Handle 0x283e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service000e/char0011
	99fa0003-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Descriptor (Handle 0xd944)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service000e/char0011/desc0013
	00002902-0000-1000-8000-00805f9b34fb
	Client Characteristic Configuration
[NEW] Primary Service (Handle 0x283e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0014
	99fa0010-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Characteristic (Handle 0x283e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0014/char0015
	99fa0011-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Descriptor (Handle 0xe284)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0014/char0015/desc0017
	00002902-0000-1000-8000-00805f9b34fb
	Client Characteristic Configuration
[NEW] Primary Service (Handle 0x283e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0018
	99fa0020-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Characteristic (Handle 0x283e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0018/char0019
	99fa0021-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Descriptor (Handle 0xfce4)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0018/char0019/desc001b
	00002902-0000-1000-8000-00805f9b34fb
	Client Characteristic Configuration
[NEW] Characteristic (Handle 0x283e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0018/char001c
	99fa0029-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Characteristic (Handle 0x283e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0018/char001e
	99fa002a-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Primary Service (Handle 0x283e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0020
	99fa0030-338a-1024-8a49-009c0215f78a
	Vendor specific
[NEW] Characteristic (Handle 0x283e)
	/org/bluez/hci0/dev_F1_0C_41_3A_4B_20/service0020/char0021
	99fa0031-338a-1024-8a49-009c0215f78a
	Vendor specific

It returns content from MANUFACTURER characteristic, but it looks like random array of bytes. Expected value is string. I handled the case with exception catch.

I went down a rabbit hole of editing your python code the other day to ignore any error that bubbled up. It always led to more and more characteristics that were different between the desks.

I pulled the latest from the master branch and submodule, deleted the repository and cloned again just to be safe.

Here is the output. Seems to be a similar error to last time, raises an error saying attribute can't be written, there must be a lot of differences between these controllers.

2020-03-19 00:44:09,497 DEBUG    MainThread __main__:main [main.py:108] Starting the application
2020-03-19 00:44:09,497 DEBUG    MainThread __main__:main [main.py:109] Logger log file: /home/hermann/Programs/LinakDeskApp/log.txt
2020-03-19 00:44:09,591 DEBUG    MainThread linakdeskapp.gui.suspenddetector.QSuspendTimer:start [suspenddetector.py:49] starting suspension detector
2020-03-19 00:44:09,593 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:setIconTheme [main_window.py:102] setting tray theme: <TrayIconTheme.WHITE: ('office-chair-gray.png', 'office-chair-white.png', 'office-chair-red.png')>
2020-03-19 00:44:09,596 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7f1da9f5a5e0>
2020-03-19 00:44:09,596 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:loadSettings [main_window.py:145] loading app state from /root/.config/arnet/LinakDeskApp.ini
2020-03-19 00:44:09,597 DEBUG    MainThread linakdeskapp.gui.app_settings_widget.AppSettingsWidget:_toggleAutoReconnectTime [app_settings_widget.py:182] setting auto reconnect timer to 60
2020-03-19 00:44:09,597 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7f1da9f5a5e0>
2020-03-19 00:44:09,597 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_tryReconnectOnStartup [main_window.py:98] trying reconnect on startup
2020-03-19 00:44:09,597 DEBUG    MainThread linakdeskapp.bt_device_connector.BTDeviceConnector:_changeConnectionStatus [bt_device_connector.py:150] changing connection state to ConnectionState.CONN_IN_PROGRESS
2020-03-19 00:44:09,597 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7f1da9f5a5e0>
2020-03-19 00:44:09,598 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7f1da9f5a5e0>
2020-03-19 00:44:09,613 DEBUG    Connect-1 linakdeskapp.bt_device_connector.ThreadWorker:run [bt_device_connector.py:288] Worker start
2020-03-19 00:44:09,615 DEBUG    Connect-1 linak_dpg_bt.connection.BTLEConnection:__init__ [connection.py:62] Constructed BTLEConnection object: <linak_dpg_bt.connection.BTLEConnection object at 0x7f1da9f64c40>
2020-03-19 00:44:09,615 DEBUG    Connect-1 linak_dpg_bt.linak_device.LinakDesk:__init__ [linak_device.py:109] Constructed LinakDesk object: <linak_dpg_bt.linak_device.LinakDesk object at 0x7f1da9f649a0>
2020-03-19 00:44:09,615 DEBUG    Connect-1 linak_dpg_bt.linak_device.LinakDesk:_connect [linak_device.py:347] Initializing the device
2020-03-19 00:44:09,615 DEBUG    Connect-1 linak_dpg_bt.connection.BTLEConnection:connect [connection.py:95] Trying to connect to 
2020-03-19 00:44:09,615 ERROR    Connect-1 linak_dpg_bt.linak_device.LinakDesk:initialize [linak_device.py:343] Initialization failed: <class 'ValueError'> Expected MAC address, got ''
Traceback (most recent call last):
  File "/home/hermann/Programs/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/linak_device.py", line 340, in initialize
    self._connect()
  File "/home/hermann/Programs/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/linak_device.py", line 348, in _connect
    with self._conn as conn:
  File "/home/hermann/Programs/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/synchronized.py", line 80, in decorator
    return func(self, *args, **kws)
  File "/home/hermann/Programs/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/connection.py", line 75, in __enter__
    self.connect()
  File "/home/hermann/Programs/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/synchronized.py", line 80, in decorator
    return func(self, *args, **kws)
  File "/home/hermann/Programs/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/connection.py", line 37, in wrapper
    return func(*args)
  File "/home/hermann/Programs/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/connection.py", line 101, in connect
    self._conn.connect(self._mac, addrType='random')
  File "/usr/lib/python3.8/site-packages/bluepy/btle.py", line 445, in connect
    self._connect(addr, addrType, iface)
  File "/usr/lib/python3.8/site-packages/bluepy/btle.py", line 423, in _connect
    raise ValueError("Expected MAC address, got %s" % repr(addr))
ValueError: Expected MAC address, got ''
2020-03-19 00:44:09,616 DEBUG    Connect-1 linakdeskapp.bt_device_connector.BTDeviceConnector:_initializeDevice [bt_device_connector.py:119] Could not connect to to device: <linak_dpg_bt.linak_device.LinakDesk object at 0x7f1da9f649a0>
2020-03-19 00:44:09,616 DEBUG    Connect-1 linakdeskapp.bt_device_connector.BTDeviceConnector:_changeConnectionStatus [bt_device_connector.py:150] changing connection state to ConnectionState.DISCONNECTED
2020-03-19 00:44:09,616 DEBUG    Connect-1 linakdeskapp.bt_device_connector.ThreadWorker:run [bt_device_connector.py:290] Worker complete
2020-03-19 00:44:09,616 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7f1da9f5a5e0>
2020-03-19 00:44:09,616 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7f1da9f5a5e0>
2020-03-19 00:44:15,289 DEBUG    MainThread linakdeskapp.bt_device_connector.BTDeviceConnector:scanDevices [bt_device_connector.py:74] Scanning bluetooth devices
2020-03-19 00:44:15,290 DEBUG    MainThread linak_dpg_bt.linak_device.LinakDesk:__del__ [linak_device.py:112] Deleting LinakDesk object: <linak_dpg_bt.linak_device.LinakDesk object at 0x7f1da9f649a0>
2020-03-19 00:44:15,290 DEBUG    MainThread linak_dpg_bt.connection.BTLEConnection:__del__ [connection.py:87] Deleting BTLEConnection object: <linak_dpg_bt.connection.BTLEConnection object at 0x7f1da9f64c40>
2020-03-19 00:44:15,291 DEBUG    MainThread linak_dpg_bt.connection.BTLEConnection:disconnect [connection.py:118] disconnecting
2020-03-19 00:44:25,562 DEBUG    MainThread linakdeskapp.bt_device_connector.BTDeviceConnector:scanDevices [bt_device_connector.py:90] Scanning finished
2020-03-19 00:44:25,564 DEBUG    MainThread linakdeskapp.gui.suspenddetector.QSuspendTimer:checkResumed [suspenddetector.py:67] resumed from suspend / hibernation after 11.169813[s]
2020-03-19 00:44:30,376 DEBUG    MainThread linakdeskapp.bt_device_connector.BTDeviceConnector:_changeConnectionStatus [bt_device_connector.py:150] changing connection state to ConnectionState.CONN_IN_PROGRESS
2020-03-19 00:44:30,376 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7f1da9f5a5e0>
2020-03-19 00:44:30,377 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7f1da9f5a5e0>
2020-03-19 00:44:30,378 DEBUG    Connect-2 linakdeskapp.bt_device_connector.ThreadWorker:run [bt_device_connector.py:288] Worker start
2020-03-19 00:44:30,379 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:__init__ [connection.py:62] Constructed BTLEConnection object: <linak_dpg_bt.connection.BTLEConnection object at 0x7f1da9f64eb0>
2020-03-19 00:44:30,379 DEBUG    Connect-2 linak_dpg_bt.linak_device.LinakDesk:__init__ [linak_device.py:109] Constructed LinakDesk object: <linak_dpg_bt.linak_device.LinakDesk object at 0x7f1da9f64c40>
2020-03-19 00:44:30,380 DEBUG    Connect-2 linak_dpg_bt.linak_device.LinakDesk:_connect [linak_device.py:347] Initializing the device
2020-03-19 00:44:30,380 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:connect [connection.py:95] Trying to connect to f1:0c:41:3a:4b:20
2020-03-19 00:44:30,623 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:connect [connection.py:112] Connected to f1:0c:41:3a:4b:20
2020-03-19 00:44:31,158 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.HEIGHT_SPEED[99FA0021-338A-1024-8A49-009C0215F78A, 0x1d]
2020-03-19 00:44:31,159 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.HEIGHT_SPEED[99FA0021-338A-1024-8A49-009C0215F78A, 0x1d] w_resp=False
2020-03-19 00:44:31,160 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.TWO[99FA0022-338A-1024-8A49-009C0215F78A, 0x20]
2020-03-19 00:44:31,160 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.TWO[99FA0022-338A-1024-8A49-009C0215F78A, 0x20] w_resp=False
2020-03-19 00:44:31,161 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.THREE[99FA0023-338A-1024-8A49-009C0215F78A, 0x23]
2020-03-19 00:44:31,161 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.THREE[99FA0023-338A-1024-8A49-009C0215F78A, 0x23] w_resp=False
2020-03-19 00:44:31,162 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.FOUR[99FA0024-338A-1024-8A49-009C0215F78A, 0x26]
2020-03-19 00:44:31,162 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.FOUR[99FA0024-338A-1024-8A49-009C0215F78A, 0x26] w_resp=False
2020-03-19 00:44:31,163 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.FIVE[99FA0025-338A-1024-8A49-009C0215F78A, 0x29]
2020-03-19 00:44:31,163 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.FIVE[99FA0025-338A-1024-8A49-009C0215F78A, 0x29] w_resp=False
2020-03-19 00:44:31,164 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.SIX[99FA0026-338A-1024-8A49-009C0215F78A, 0x2c]
2020-03-19 00:44:31,164 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.SIX[99FA0026-338A-1024-8A49-009C0215F78A, 0x2c] w_resp=False
2020-03-19 00:44:31,165 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.SEVEN[99FA0027-338A-1024-8A49-009C0215F78A, 0x2f]
2020-03-19 00:44:31,165 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.SEVEN[99FA0027-338A-1024-8A49-009C0215F78A, 0x2f] w_resp=False
2020-03-19 00:44:31,166 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.EIGHT[99FA0028-338A-1024-8A49-009C0215F78A, 0x32]
2020-03-19 00:44:31,166 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.EIGHT[99FA0028-338A-1024-8A49-009C0215F78A, 0x32] w_resp=False
2020-03-19 00:44:31,167 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:284] Reading char: Characteristic.MASK[99FA0029-338A-1024-8A49-009C0215F78A, 0x35]
2020-03-19 00:44:31,353 ERROR    Connect-2 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:292] Got exception from bluepy while making a request: Bluetooth command failed (code: 1, error: Invalid handle)
2020-03-19 00:44:31,353 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:297] trying to access characteristic by uuid: 99FA0029-338A-1024-8A49-009C0215F78A
2020-03-19 00:44:33,107 DEBUG    Connect-2 linak_dpg_bt.linak_device.LinakDesk:_connect [linak_device.py:377] Received mask: Mask[ActuatorType.Desk 0x1]
2020-03-19 00:44:33,108 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:284] Reading char: Characteristic.DEVICE_NAME[00002A00-0000-1000-8000-00805F9B34FB, 0x3]
2020-03-19 00:44:33,205 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:289] Got value [0x64 0x65 0x73 0x6B 0x64 0x65 0x73 0x6B]
2020-03-19 00:44:33,205 DEBUG    Connect-2 linak_dpg_bt.linak_device.LinakDesk:_connect [linak_device.py:381] Received name: deskdesk
2020-03-19 00:44:33,206 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:284] Reading char: Characteristic.MANUFACTURER[00002A29-0000-1000-8000-00805F9B34FB, 0x18]
2020-03-19 00:44:33,302 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:289] Got value [0x8A 0xF7 0x15 0x02 0x9C 0x00 0x49 0x8A 0x24 0x10 0x8A 0x33 0x20 0x00 0xFA 0x99]
2020-03-19 00:44:33,303 ERROR    Connect-2 linak_dpg_bt.linak_device.LinakDesk:_connect [linak_device.py:390] Reading manufacturer failed: <class 'UnicodeDecodeError'> 'utf-8' codec can't decode byte 0x8a in position 0: invalid start byte
2020-03-19 00:44:33,303 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:284] Reading char: Characteristic.MODEL_NUMBER[00002A24-0000-1000-8000-00805F9B34FB, 0x1a]
2020-03-19 00:44:33,400 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:read_characteristic_by_enum [connection.py:289] Got value [0x5E 0x08 0x00 0x00]
2020-03-19 00:44:33,400 DEBUG    Connect-2 linak_dpg_bt.linak_device.LinakDesk:_connect [linak_device.py:396] Received model: ^
2020-03-19 00:44:33,400 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.DPG[99FA0011-338A-1024-8A49-009C0215F78A, 0x14]
2020-03-19 00:44:33,400 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.DPG[99FA0011-338A-1024-8A49-009C0215F78A, 0x14] w_resp=False
2020-03-19 00:44:33,400 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.ERROR[99FA0003-338A-1024-8A49-009C0215F78A, 0x10]
2020-03-19 00:44:33,401 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.ERROR[99FA0003-338A-1024-8A49-009C0215F78A, 0x10] w_resp=False
2020-03-19 00:44:33,401 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:231] Subscribing to Characteristic.SERVICE_CHANGED[00002A05-0000-1000-8000-00805F9B34FB, 0xa]
2020-03-19 00:44:33,401 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:subscribe_to_notification_enum [connection.py:236] Writing value <class 'bytes'>:0x01 0x00 to Characteristic.SERVICE_CHANGED[00002A05-0000-1000-8000-00805F9B34FB, 0xa] w_resp=False
2020-03-19 00:44:33,401 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:_send_command_single [connection.py:225] Sending DPGCommand[USER_ID, None]: 0x7F 0x86 0x00 to Characteristic.DPG[99FA0011-338A-1024-8A49-009C0215F78A, 0x14] w_resp=True
2020-03-19 00:44:33,546 ERROR    Connect-2 linak_dpg_bt.connection:wrapper [connection.py:39] bluetooth exception occurred: <class 'bluepy.btle.BTLEGattError'> Bluetooth command failed (code: 3, error: Attribute can't be written)
2020-03-19 00:44:33,546 DEBUG    Connect-2 linak_dpg_bt.connection.BTLEConnection:disconnect [connection.py:118] disconnecting
2020-03-19 00:44:33,547 ERROR    Connect-2 linak_dpg_bt.linak_device.LinakDesk:initialize [linak_device.py:343] Initialization failed: <class 'bluepy.btle.BTLEGattError'> Bluetooth command failed (code: 3, error: Attribute can't be written)
Traceback (most recent call last):
  File "/home/hermann/Programs/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/linak_device.py", line 340, in initialize
    self._connect()
  File "/home/hermann/Programs/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/linak_device.py", line 402, in _connect
    conn.send_dpg_read_command( DPGCommandType.USER_ID )
  File "/home/hermann/Programs/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/synchronized.py", line 80, in decorator
    return func(self, *args, **kws)
  File "/home/hermann/Programs/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/connection.py", line 37, in wrapper
    return func(*args)
  File "/home/hermann/Programs/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/connection.py", line 188, in send_dpg_read_command
    return self._send_command_repeated(linak_service.Characteristic.DPG, dpgCommand)
  File "/home/hermann/Programs/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/connection.py", line 209, in _send_command_repeated
    self._send_command_single(characteristicEnum, commandObj, with_response)
  File "/home/hermann/Programs/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/connection.py", line 226, in _send_command_single
    return self._write_to_characteristic( characteristicEnum.handle(), value, with_response=with_response)
  File "/home/hermann/Programs/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/connection.py", line 244, in _write_to_characteristic
    succeed = self._write_to_characteristic_raw(handle, value, with_response)
  File "/home/hermann/Programs/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/connection.py", line 250, in _write_to_characteristic_raw
    self._conn.writeCharacteristic( handle, value, withResponse=with_response)
  File "/usr/lib/python3.8/site-packages/bluepy/btle.py", line 543, in writeCharacteristic
    return self._getResp('wr')
  File "/usr/lib/python3.8/site-packages/bluepy/btle.py", line 407, in _getResp
    resp = self._waitResp(wantType + ['ntfy', 'ind'], timeout)
  File "/usr/lib/python3.8/site-packages/bluepy/btle.py", line 368, in _waitResp
    raise BTLEGattError("Bluetooth command failed", resp)
bluepy.btle.BTLEGattError: Bluetooth command failed (code: 3, error: Attribute can't be written)
2020-03-19 00:44:33,548 DEBUG    Connect-2 linakdeskapp.bt_device_connector.BTDeviceConnector:_initializeDevice [bt_device_connector.py:119] Could not connect to to device: <linak_dpg_bt.linak_device.LinakDesk object at 0x7f1da9f64c40>
2020-03-19 00:44:33,548 DEBUG    Connect-2 linakdeskapp.bt_device_connector.BTDeviceConnector:_changeConnectionStatus [bt_device_connector.py:150] changing connection state to ConnectionState.DISCONNECTED
2020-03-19 00:44:33,548 DEBUG    Connect-2 linakdeskapp.bt_device_connector.ThreadWorker:run [bt_device_connector.py:290] Worker complete
2020-03-19 00:44:33,548 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7f1da9f5a5e0>
2020-03-19 00:44:33,548 DEBUG    MainThread linakdeskapp.gui.main_window.MainWindow:_updateTrayIcon [main_window.py:125] setting tray icon office-chair-gray.png <PyQt5.QtGui.QIcon object at 0x7f1da9f5a5e0>
2020-03-19 00:47:09,945 DEBUG    MainThread linakdeskapp.gui.sigint:_interrupt_handler [sigint.py:25] Interrupt received: 2

2020-03-19 00:47:09,952 INFO     MainThread __main__:main [main.py:147] Calculation time: 180454.64730263ms
2020-03-19 00:47:09,955 DEBUG    MainThread linak_dpg_bt.linak_device.LinakDesk:__del__ [linak_device.py:112] Deleting LinakDesk object: <linak_dpg_bt.linak_device.LinakDesk object at 0x7f1da9f64c40>
2020-03-19 00:47:09,955 DEBUG    MainThread linak_dpg_bt.connection.BTLEConnection:__del__ [connection.py:87] Deleting BTLEConnection object: <linak_dpg_bt.connection.BTLEConnection object at 0x7f1da9f64eb0>

One thing You can do in this situation is or use my MITM tool I mentioned (to analyze it dynamically) earlier or try to decompile Android APK application and analyze source code statically.

@anetczuk I'll most likely try to do that, thanks for all the help

rhyst commented

@HermannBjorgvin Did you get anywhere with this?

@anetczuk I have the same desk, and am in the same position as @HermannBjorgvin. I do also have the decompiled source for the app used to control this desk ("Desk Control"), so I can map some of the UUIDs to helpful sounding consts like "MASK" and "COMMAND".

I found that I also had to wrap the model number in a try/catch but then I get the same error.

2020-05-26 20:54:08,574 DEBUG    Connect-1 linak_dpg_bt.connection.BTLEConnection:_send_command_single [connection.py:225] Sending DPGCommand[USER_ID, None]: 0x7F 0x86 0x00 to Characteristic.DPG[99FA0011-338A-1024-8A49-009C0215F78A, 0x14] w_resp=True
2020-05-26 20:54:08,672 ERROR    Connect-1 linak_dpg_bt.connection:wrapper [connection.py:39] bluetooth exception occurred: <class 'bluepy.btle.BTLEGattError'> Bluetooth command failed (code: 3, error: Attribute can't be written)

In the decompiled app source this UUID corresponds to the "DPG" const, and the GATTBrowser app lists the following poroperties for that characteristic:

Read Write Without Response Write Notify

Which seems to suggest it is writeable.

I also had a look at the MITM app you wrote, however I havent got it working yet as I don't know which dbus library it wants (not dbus-python apparently?)

Sorry for the info dump, but would be very keen to help get this working for my desk if you have the time to point me in the right direction.

I got my IKEA IDΓ…SEN yesterday. Here's a TL;DR of what I tried (scroll below for some working stuff):

"Device discovery" via the GUI is broken. First of all, there's this exception:

ERROR    Connect-1 linak_dpg_bt.linak_device.LinakDesk:initialize [linak_device.py:343] Initialization failed: <class 'ValueError'> Expected MAC address, got ''
Traceback (most recent call last):
  File "/home/jkt/work/prog/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/linak_device.py", line 340, in initialize
    self._connect()
  File "/home/jkt/work/prog/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/linak_device.py", line 348, in _connect
    with self._conn as conn:
  File "/home/jkt/work/prog/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/synchronized.py", line 80, in decorator
    return func(self, *args, **kws)
  File "/home/jkt/work/prog/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/connection.py", line 75, in __enter__
    self.connect()
  File "/home/jkt/work/prog/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/synchronized.py", line 80, in decorator
    return func(self, *args, **kws)
  File "/home/jkt/work/prog/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/connection.py", line 37, in wrapper
    return func(*args)
  File "/home/jkt/work/prog/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/connection.py", line 101, in connect
    self._conn.connect(self._mac, addrType='random')
  File "/home/jkt/work/prog/LinakDeskApp/_py3.6/lib64/python3.6/site-packages/bluepy/btle.py", line 445, in connect
    self._connect(addr, addrType, iface)
  File "/home/jkt/work/prog/LinakDeskApp/_py3.6/lib64/python3.6/site-packages/bluepy/btle.py", line 423, in _connect
    raise ValueError("Expected MAC address, got %s" % repr(addr))
ValueError: Expected MAC address, got ''

I have no clue what that means.

But the app appears to work well enough up to triggering a device scan, which can find my desk. When I try to connect, though, it fails on these invalid Unicode data for the model. After ignoring that, it fails on DPGCommandType.USER_ID, also on DPGCommandType.GET_SETUP and DPGCommandType.PRODUCT_INFO, and when reading capabilities. It seems that the only useful info that can be read is Characteristic.MASK (on a second attempt only, i.e. via UUID 99FA0029-338A-1024-8A49-009C0215F78A) which says Mask[ActuatorType.Desk 0x1]. One can also read Characteristic.DEVICE_NAME[00002A00-0000-1000-8000-00805F9B34FB, 0x3] which corresponds to the BT device name.

I gave up on generic code and went directly to direct control at that point, and have some good news:

Direct manual control via BT works

  • Notifications on GATT 99fa0021-338a-1024-8a49-009c0215f78a work, it looks like a tuple of (position, speed) where both are little-endian int16_t. That's good!
  • Absolute positioning via 99FA0031-338A-1024-8A49-009C0215F78A doesn't appear to work out-of-the-box. I don't know if I have to enable these somehow (got to RTFS), or if the HW just doesn't support them.
  • I can ask the desk to go "one step up" or "one step down" via 99FA0002-338A-1024-8A49-009C0215F78A. These feel like roughly one-second steps, and I can also cancel this movement. This probably means that a control loop can be built.

It's already too late now :), so I'll see later if I can cleanly implement some discovery bypass, or if I'll just implement some trivial positioning script with no GUI for me.

Thanks for your awesome work on reverse engineering these controllers.

rhyst commented

@jktjkt That's great news! Very impressive that you made this progress after one day with the desk πŸ˜„ I'd be very grateful if you could post even what you have so far as I suspect I'll want to script it anyway.

I also managed to "subscribe" to the notifications directly in bluetoothctlbut had no idea what the hex that came out meant.

rhyst commented

I've managed to get something very basic working. I used the gatt library after trying out quite a few and finding this to be the only one that worked for me.

This will print out the position, speed tuple when the desk moves and also has an example of writing the UP or DOWN commands to the correct characteristic.

import gatt
import struct

# Pick your adapter
manager = gatt.DeviceManager(adapter_name='hci1')


class AnyDevice(gatt.Device):
    def connect_succeeded(self):
        super().connect_succeeded()
        print("[%s] Connected" % (self.mac_address))

    def connect_failed(self, error):
        super().connect_failed(error)
        print("[%s] Connection failed: %s" % (self.mac_address, str(error)))

    def disconnect_succeeded(self):
        super().disconnect_succeeded()
        print("[%s] Disconnected" % (self.mac_address))

    def services_resolved(self):
        super().services_resolved()

        print("[%s] Resolved services" % (self.mac_address))
        for service in self.services:
            print("[%s]  Service [%s]" % (self.mac_address, service.uuid))
            for characteristic in service.characteristics:
                print("[%s]    Characteristic [%s]" %
                      (self.mac_address, characteristic.uuid))
                if characteristic.uuid == '99fa0021-338a-1024-8a49-009c0215f78a':
                    characteristic.enable_notifications()
                if characteristic.uuid == '99fa0002-338a-1024-8a49-009c0215f78a':
                    # DOWN
                    # characteristic.write_value(struct.pack("<H", 70))
                    # UP
                    characteristic.write_value(struct.pack("<H", 71))

    def characteristic_value_updated(self, characteristic, value):
        print("Update {}: {}".format(
            characteristic.uuid, struct.unpack("<HH", value)))

    def characteristic_write_value_succeeded(self, characteristic):
        print("SUCCESS")

    def characteristic_write_value_failed(self, characteristic, error):
        print("Error ", error)


device = AnyDevice(mac_address='MAC_ADDRESS', manager=manager)
device.connect()

manager.run()

I will probably end up scripting something to switch between two positions by sending the up/down commands and watching the notification values.

I also had a look at the MITM app you wrote, however I havent got it working yet as I don't know which dbus library it wants (not dbus-python apparently?)

@rhyst MITM requires python-dbus from Linux repo (try apt for it) and it works with Python 2. As far as I remember the application had problems with dbus packages from pip. Moreover committed small changes to MITM, try if it works.

I found that I also had to wrap the model number in a try/catch but then I get the same error.

2020-05-26 20:54:08,574 DEBUG    Connect-1 linak_dpg_bt.connection.BTLEConnection:_send_command_single [connection.py:225] Sending DPGCommand[USER_ID, None]: 0x7F 0x86 0x00 to Characteristic.DPG[99FA0011-338A-1024-8A49-009C0215F78A, 0x14] w_resp=True
2020-05-26 20:54:08,672 ERROR    Connect-1 linak_dpg_bt.connection:wrapper [connection.py:39] bluetooth exception occurred: <class 'bluepy.btle.BTLEGattError'> Bluetooth command failed (code: 3, error: Attribute can't be written)

In the decompiled app source this UUID corresponds to the "DPG" const, and the GATTBrowser app lists the following poroperties for that characteristic:

Read Write Without Response Write Notify

Which seems to suggest it is writeable.

@rhyst From the line:

Characteristic.DPG[99FA0011-338A-1024-8A49-009C0215F78A, 0x14]

UUID is not as important. The important thing is the handler 0x14 -- app uses it to identify BT objects. Verify in GATTBrowser if UUID in Your device matches the handler. If not then try to change handler value.

rhyst commented

Ah, I had been trying MITM with python2, though I think there;s not much point in using it now I've got the decompiled app.

In GATTBrowser I can see some values that look like the handler. They are:

00002a05-0000-1000-8000-00805f9b34fb INDICATE? 0x20
99fa0002-338a-1024-8a49-009c0215f78a COMMAND 0x0c
99fa0003-338a-1024-8a49-009c0215f78a ERROR 0x12
99fa0011-338a-1024-8a49-009c0215f78a DPG 0x1e
99fa0021-338a-1024-8a49-009c0215f78a ONE (REFERENCE_OUTPUT) 0x12
99fa0029-338a-1024-8a49-009c0215f78a MASK 0x02
99fa002a-338a-1024-8a49-009c0215f78a DETECT_MASK 0x02
99fa0030-338a-1024-8a49-009c0215f78a ONE (REFERENCE_INPUT) 0x0c

I set

    DPG         = ("99FA0011-338A-1024-8A49-009C0215F78A", 0x1E)

in linak_service.py but got the same error.

"Device discovery" via the GUI is broken. First of all, there's this exception:

ERROR    Connect-1 linak_dpg_bt.linak_device.LinakDesk:initialize [linak_device.py:343] Initialization failed: <class 'ValueError'> Expected MAC address, got ''
Traceback (most recent call last):
  File "/home/jkt/work/prog/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/linak_device.py", line 340, in initialize
    self._connect()
  File "/home/jkt/work/prog/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/linak_device.py", line 348, in _connect
    with self._conn as conn:
  File "/home/jkt/work/prog/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/synchronized.py", line 80, in decorator
    return func(self, *args, **kws)
  File "/home/jkt/work/prog/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/connection.py", line 75, in __enter__
    self.connect()
  File "/home/jkt/work/prog/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/synchronized.py", line 80, in decorator
    return func(self, *args, **kws)
  File "/home/jkt/work/prog/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/connection.py", line 37, in wrapper
    return func(*args)
  File "/home/jkt/work/prog/LinakDeskApp/lib/linak_bt_desk/linak_dpg_bt/connection.py", line 101, in connect
    self._conn.connect(self._mac, addrType='random')
  File "/home/jkt/work/prog/LinakDeskApp/_py3.6/lib64/python3.6/site-packages/bluepy/btle.py", line 445, in connect
    self._connect(addr, addrType, iface)
  File "/home/jkt/work/prog/LinakDeskApp/_py3.6/lib64/python3.6/site-packages/bluepy/btle.py", line 423, in _connect
    raise ValueError("Expected MAC address, got %s" % repr(addr))
ValueError: Expected MAC address, got ''

I have no clue what that means.

@jktjkt When started, app tries to connect to recent device. You started it for the first time, so it couldn't connect to "" (empty) address.
To connect to device You have to perform scanning ("File>Connect to...") and then select Your desk. It requires additional privileges, so You can start with root and connect to desk (then reconnecting won't need root) or follow README>Privileges section to give privileges to Python's bluepy.

But the app appears to work well enough up to triggering a device scan, which can find my desk. When I try to connect, though, it fails on these invalid Unicode data for the model. After ignoring that, it fails on DPGCommandType.USER_ID, also on DPGCommandType.GET_SETUP and DPGCommandType.PRODUCT_INFO, and when reading capabilities. It seems that the only useful info that can be read is Characteristic.MASK (on a second attempt only, i.e. via UUID 99FA0029-338A-1024-8A49-009C0215F78A) which says Mask[ActuatorType.Desk 0x1]. One can also read Characteristic.DEVICE_NAME[00002A00-0000-1000-8000-00805F9B34FB, 0x3] which corresponds to the BT device name.

In general it seems that IKEA model differs significantly from the one I've got. Sorry, but do not have access to Ikea device, so cannot help a lot.

* I can ask the desk to go "one step up" or "one step down" via `99FA0002-338A-1024-8A49-009C0215F78A`. These feel like roughly one-second steps, and I can also cancel this movement. This probably means that a control loop can be built.

Yes, it works like this: You send a packet via bluetooth to move device a bit, then to sustain the movement You have to continuously resend move packet. It is implemented in this way in original Android app and I made it the same.
My device have "move to" feature, but I don't remember if internally it is implemented in similar fashion (with loop) or it requires just one packet.

Today I've tested a python implementation of Ikea Idasen command via BT:
https://github.com/cskollar/idasen2mqtt/blob/master/idasen2mqtt.py
it works like a charm. You may try the BT IDs from there?

Ah, I had been trying MITM with python2, though I think there;s not much point in using it now I've got the decompiled app.

@rhyst I used MITM as addition to decompiled sources, because it was quite hard to figure out "dynamic" properties of application.

In GATTBrowser I can see some values that look like the handler. They are:

00002a05-0000-1000-8000-00805f9b34fb INDICATE? 0x20
99fa0002-338a-1024-8a49-009c0215f78a COMMAND 0x0c
99fa0003-338a-1024-8a49-009c0215f78a ERROR 0x12
99fa0011-338a-1024-8a49-009c0215f78a DPG 0x1e
99fa0021-338a-1024-8a49-009c0215f78a ONE (REFERENCE_OUTPUT) 0x12
99fa0029-338a-1024-8a49-009c0215f78a MASK 0x02
99fa002a-338a-1024-8a49-009c0215f78a DETECT_MASK 0x02
99fa0030-338a-1024-8a49-009c0215f78a ONE (REFERENCE_INPUT) 0x0c

I set

    DPG         = ("99FA0011-338A-1024-8A49-009C0215F78A", 0x1E)

in linak_service.py but got the same error.

Hard to say what's going on. Try to start with small snippets.
As far as I remember, original application used two kinds of users: guest and non-guest, and it was possible to connect to device without possibility of moving the desk. Maybe You have achieved this state?

@rhyst @jktjkt @fireto Have you guys managed to get any further? I am also on the same IKEA desk and would love to get this working. I can help further with debugging as well if needed

rhyst commented

@william-reed I made a script from scratch (using what I learned from this project) as I did not need a gui so if that's good enough for you: https://github.com/rhyst/idasen-controller

@rhyst thank you thank you thank you!!! Making dreams come true!!!
image