LinakDeskApp: Bluetooth command failed (code: 1, error: Invalid handle)
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
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 30 (13 by maintainers)
@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
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:
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 onDPGCommandType.GET_SETUP
andDPGCommandType.PRODUCT_INFO
, and when reading capabilities. It seems that the only useful info that can be read isCharacteristic.MASK
(on a second attempt only, i.e. via UUID99FA0029-338A-1024-8A49-009C0215F78A
) which saysMask[ActuatorType.Desk 0x1]
. One can also readCharacteristic.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
99fa0021-338a-1024-8a49-009c0215f78a
work, it looks like a tuple of (position, speed) where both are little-endianint16_t
. That’s good!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.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.
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.
@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
bluetoothctl
but had no idea what the hex that came out meant.@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.
In the decompiled app source this UUID corresponds to the “DPG” const, and the GATTBrowser app lists the following poroperties for that characteristic:
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.
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.
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.
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.