Desky Standing Desk (ESPHome) [Works with Desky, Uplift, Jiecang, Assmann & others]

Not sure about how valid these values are yet. First time I’ve done this. Not sure if it’s wiring or how I somehow need to configure the custom UART Text sensor?

[12:12:46][D][text_sensor:067]: 'uart_readline': Sending state '!\xfe!!\xde\xdf!!\xe5\xffK\xa1)\xcb\xffK!\xedK!!\xed!!\xed\xffK!!\x92\xff\xcb!%\xa5\xfbO\xa1i\xdaZ\xcb\xa1N\xfb'

Getting lots of help from ssieb over on ESPHome Discord now…

1 Like

On this, there does exist ESP32 Relay Modules (up to 16 channels) with optocouplers that can be used to control higher voltage circuits.

There’s a working solution to this coming in the next few weeks…

2 Likes

Interested in finding out more too - it looks like most of these units use the same / compatible controllers / keypads - would be great to have the pin-outs fully documented so we can develop our own accessories.

Would be really interested in the alternate port, which appears to be for wifi/bluetooth modules…

Option #1: Pass-Through Dongle (Simpler)

Update note 2022-07-03: Might be worth looking over Option #2 config as I’ve made some enhancments/refinements there.


I’m going to keep refining/editing this post as the main ‘how to’.

The majority of credit for the solution so far goes to @ssieb . He generously donated his time and knowledge to decode the UART protocol and write the ESPHome custom component (I don’t know any C++, or much about UART either). He doesn’t have one of these desks. He may be generous enough to add some more features or otherwise collaborate on it’s development if we are nice😉.

Key links:

Hardware: We build ourselves a Dongle from the RJ45 port which “passes-through” 8 of 8 wires between the controller and the control panel and fork-off 6 of 8 to a d1 mini (or esp32 etc)

Parts list:

Soldering

If you are allergic to soldering (I used to be, but worked through it;) you could do this solder free if you pick an esp with pins already on it and buy some dupont cables.

Software:

  • Use Sseib’s custom component and some of my config (optional).
  • You might want to start with just using ssieb’s less bloated config (but make sure you invert the pins). Then maybe read through my config and use what you want.
  • Also Sseib’s config works in mm, whereas I’ve adjust mine to generally be in cm.

Edit: 2022-06-05 Some of the config is a little dated since ssieb deployed some new features l requested. Look at his base config first.

####################################################################################################
##Notes/Info
####################################################################################################

## Home Assistant Thread: https://community.home-assistant.io/t/desky-standing-desk/383790/3
## ssieb who generously donated his time and knowledge to developing the custom component may offer some support on the Discord thread (please read both threads first).
## https://discord.com/channels/429907082951524364/952464939480645642

#Notes:
# 1. Use this component at own risk. It has not had extensive testing. May void warranty or cause desk faults etc.
# 2. This controller may bypass desk safety features like collision detection.
# 3. This component doesn't know about the values stored in your desk. Values in this config are (and must be) set independently.
# 4. ssieb's solution may be a lot simpler and cleaner for most people. I've cobbled together some more features in this config because I can't programn in C++.


#Troubleshooting Tips: 
#If you ever get a flashing ASr message, you might need to reset your desk.
#https://desky.com.au/blogs/news/reset-standing-desk-control-panel#:~:text=When%20ready%2C%20press%20and%20hold,Hooray!


#TODO 
#Ask ssieb to make change requests (move logic to component code)
  # Invert pins
  # Get Desk Height On Boot
  # Interlock Up/Down Pins (If not done already)
  # Interrupt/stop movement function (Stop desk motion)

#other
  # Test collision detection
  # Limit external component fetch to just desky? 
  # Fix Desk Is moving on Boot.

esphome:
  name: desky-d1mini-v2
  platform: ESP8266
  board: d1_mini #pinout: https://i0.wp.com/randomnerdtutorials.com/wp-content/uploads/2019/05/ESP8266-WeMos-D1-Mini-pinout-gpio-pin.png?quality=100&strip=all&ssl=1
  on_boot:
    priority: -100.0
    then:
    #Request a desk height update after boot.
      - delay: 5s
      - switch.turn_on: wake_desk_and_get_height
    
wifi:
  ssid: "NotTellingYouThat"
  password: "NopeItsMySecret"

api:
ota:

logger:
  # level: VERY_VERBOSE ##Uncomment to see UART debug messages 

external_components:
#Fetch ssieb's custom component# https://github.com/ssieb/custom_components/tree/master/components/desky
  - source:
      type: git
      url: https://github.com/ssieb/custom_components
    components: [ desky ]

uart:
  - id: desk_uart
    baud_rate: 9600
    rx_pin: 1 #Labelled TX on my D1mini clone (mislabelled?)
    ##You can uncomment the debug section below to see UART messages.
    # debug:
      # direction: RX
      # dummy_receiver: true
      # after:
        # bytes: 4
      # sequence:     
        # - lambda: UARTDebug::log_int(direction, bytes, ',');
 
desky:
  id: my_desky
  ####################################################################################
  ##Uncomment this block to use Ssieb's move_to componet function.
  # up:    
    # number: 4 #D2
    # inverted: true 
  # down:  
    # number: 5 #D1
    # inverted: true
  # stopping_distance: 15  # optional distance from target to turn off moving, default 15  
  ####################################################################################
  height:  # Sensor publishing the current height
    name: Desky Height
    id: desky_height
    accuracy_decimals: 1
    unit_of_measurement: cm
    #any other sensor options
    filters:
    - delta: 0.05 #Only send values to HA if they change
    - throttle: 200ms #Limit values sent to Ha to 5 per sec.
    - multiply: 0.1 #convert from mm to cm
    on_value:
      then:
          #If the value changes, then the desk is moving
        - binary_sensor.template.publish:
            id: desky_is_moving
            state: ON
        - delay: 300ms
          #Assume it's stopped moving if no height changes after a short time.
        - binary_sensor.template.publish:
            id: desky_is_moving
            state: Off
            
binary_sensor:
  - platform: template
    id: desky_is_moving
    name: "Desky Is Moving"
    filters:
      - delayed_off: 400ms
    #If the desk isn't moving for a bit we better turn off attempts at movement. It's like poor man's collision detection? 
    on_release:
      then:
        - button.press: desky_stop_desk

button: 
#Stop movement 
  - platform: template
    name: Stop Desk
    id: desky_stop_desk
    on_press:
      then:
        - switch.turn_off: raise_desk
        - switch.turn_off: lower_desk

#Move to function
  - platform: template
    name: Go To Desky Height x
    id: go_to_desky_preset_height_x
    on_press:
      then:
      ##Option 1: Uncomment to use Ssieb's move_to componet functions
        # - lambda: id(my_desky).move_to(id(desky_target_height).state*10);  

        
      ##Option 2: Uncomment to use Mahko's lambda alternative 
      #Check if we need to move desk up or down from current position      
        if:
          condition:
          #Current height is more than target height, then move desk down
            lambda: |-
              return id(desky_target_height).state < id(desky_height).state;
          then:
            - switch.turn_on: lower_desk
            - wait_until:
              #Run until the difference between current and target state is < stopping distance 
                condition:
                  lambda: return abs((id(desky_height).state - (id(desky_target_height).state)))<(id(stopping_distance_cm).state);
            - switch.turn_off: lower_desk
          else:
          #Current height is less than target height, move desk up
            - switch.turn_on: raise_desk
            - wait_until:
                condition:
                  lambda: return abs((id(desky_height).state - (id(desky_target_height).state)))<(id(stopping_distance_cm).state);
                  #Run until the difference between current and target state is <0.3cm
            - switch.turn_off: raise_desk


number:
#Target Height ("Move desk to height x").
    #You should probably limit the range you can move the desk to to within the limits you've set via the control panel, perhaps offset a little within the range.
    #Sending commands higher/lower than this may cause error messages and require desk reset (or worse).
  - platform: template
    id: desky_target_height
    name: "Desky Target Height"
    optimistic: true
    unit_of_measurement: cm
    min_value: 80
    max_value: 130.0
    step: 0.1
    
#Offset correction - Adjust until you get the best accuracy. 
#The desk keeps moving for a little while after the up/down pins are released and we try to account for this.
#1.5cm was about right on mine
  - platform: template
    name: "Desky Stopping Distance cm"
    id: stopping_distance_cm
    unit_of_measurement: cm
    optimistic: true
    min_value: 0
    max_value: 2
    step: 0.1
    restore_value: true
    initial_value: 1.5
    
###############################################
#Define some preset heights.
###############################################
#You can freely define as many adjustable presets as you like.
#These are all seperate/independant of what you've set via the control panel (we can't retrieve them currently).
 
#Standing Height #1 - Set a standing height. 
  - platform: template
    id: desky_standing_height_1
    name: "Desky Standing Height 1"
    optimistic: true
    unit_of_measurement: cm
    #Limit the range
    min_value: 120
    max_value: 130
    step: 0.1
    restore_value: true
    initial_value: 124
    
#Sitting Height #1 - Set a sitting height. This is independant of what you've set via the control panel.
  - platform: template
    id: desky_sitting_height_1
    name: "Desky Sitting Height 1"
    optimistic: true
    unit_of_measurement: cm
    #Limit the range
    min_value: 79.7
    max_value: 82
    step: 0.1
    restore_value: true
    initial_value: 79.9


      
switch:
#wake up ther desk and request it sends its height 
  - platform: gpio
    id: wake_desk_and_get_height
    name: "Request Desk Height"
    pin:
      number: D5
      inverted: true
    on_turn_on:
    - delay: 100ms
    - switch.turn_off: wake_desk_and_get_height

#Raise the desk 
  - platform: gpio
    id: raise_desk
    name: "Raise Desk"
    pin:
      number: D2
      # mode: INPUT_PULLUP
      inverted: true
    interlock: lower_desk
    on_turn_on:
    #Auto off after 15s just in case
    - delay: 15s
    - switch.turn_off: raise_desk
#Lower the desk 
  - platform: gpio
    id: lower_desk
    name: "Lower Desk" 
    pin:
      number: D1
      # mode: INPUT_PULLUP
      inverted: true
    interlock: raise_desk
    on_turn_on:
   #Auto off after 15s just in case
    - delay: 15s
    - switch.turn_off: lower_desk
  


   







7 Likes

I thought I’d put up what I’ve got so far so that others can start using/contributing too…

This is looking awesome!
I can’t personally contribute to it, unfortunately, but thanks for having the determination to follow through with this. The Home Assistant and smart home community in general are so inspiring.
Will be sure to give thanks to ssieb!

2 Likes

Would you be able to provide a parts list for your implementation (using the d1 mini)?
I’m curious where you got the main housing from.

Hey, I’ve added a parts list to my solution post above. Sing out if you have any Q’s.

2 Likes

This post is some info on the rj12 Bluetooth dongle port.

I’ve been able to decode the UART height messages coming from the controller to the dongle port (building on sseib’s work). They are similar to the ones on the rj45 port.

But there doesn’t appear to be dedicated wires for raising/lowering the desk on this port. You can see in the teardown link below that the Bluetooth dongle has 4 wires. Earth, power, tx and (very likely) rx. I asked the company for the protocol for controlling it but they would not provide it. And I don’t believe you can actually purchase the dongle to sniff commands coming from the dongle to the desk. Therefore there is no known way to control the desk over this port, only get height readings.

So I abandoned this port and went forward with my “pass-through” solution on the rj45 port.

But here is some consolidated info I have on the RJ12 port anyway.

The dongle:
https://en.jiecang.com/product/131.html
Someone else’s tear-down:
https://fccid.io/2ANKDJCP35NBLT/Internal-Photos/Internal-Photos-3727739

Jiecang, Desky, and Uplift apps on the Google play store give you some hints as to the commands possible.

https://www.upliftdesk.com/uplift-desk-connect/

This guy appears to have built something interesting:

To see messages coming from the bluetooth port youm can use this UART debugging config.
I’ve forgotten and lost the pin schema though unfortunately

uart:
  - id: uart_bus2
    tx_pin: GPIO17
    rx_pin: GPIO16
    baud_rate: 9600
    debug:
      direction: BOTH
      dummy_receiver: true
      after:
        bytes: 9
      sequence:     
        - lambda: UARTDebug::log_int(direction, bytes, ',');

Then desk height = ( byte 5 * 256 ) + byte 6
= (5*256) + 41 = 1321mm = 132.1cm

Sample messages:

[20:40:27][D][uart_debug:176]: <<< 242,242,1,3,3,63,15,85,126
[20:40:27][D][uart_debug:176]: <<< 242,242,1,3,3,56,15,78,126
[20:40:27][D][uart_debug:176]: <<< 242,242,1,3,3,48,15,70,126
[20:40:28][D][uart_debug:176]: <<< 242,242,1,3,3,42,15,64,126
[20:40:28][D][uart_debug:176]: <<< 242,242,1,3,3,38,15,60,126
[20:40:28][D][uart_debug:176]: <<< 242,242,1,3,3,35,15,57,126
[20:40:28][D][uart_debug:176]: <<< 242,242,1,3,3,31,15,53,126
[20:40:29][D][uart_debug:176]: <<< 242,242,1,3,3,29,15,51,126
[20:40:29][D][uart_debug:176]: <<< 242,242,1,3,3,29,15,51,126

Yeah I reached out to the company to see if they could point me at a retailer of the dongle here’s in the UK, but they weren’t particularly helpful.

My friend purchased one in Australia, and doesn’t use it :rofl:

Might have to try either steal it off him, or get him to analyze it for me some time.

In the middle of a house move at the moment, but I’ll be reporting back anything I find.

At the very least, knowing the height without passthrough would already be a win for me, but I’d love to tell Siri to set the desk height.

1 Like

Actually, just found these guys, giving this dongle a try, I suspect they’ll all work the same.

Ah you mention you’re paying AUD so you’re probably in Australia. I think you might be able to get the dongle from zendesks.com.au - might need to reach out to support though. I’ve contacted them too, will let you know if they respond.

1 Like

I believe you need to find a dongle for Jiecang controllers (which is what for example Desky and Uplift use) if that is what you have, as opposed to Linak (which I think it another manufacturer, and they’ll very likely have a different protocol)

Ah. Well I guess I’ll find out. Zendesks confirmed via support that they sell the dongle, bit not sure which one they have. I’ll let you know how things go with the dongle I ordered once it arrives. Hope you’re wrong! :rofl:

How did you go?

They informed me the dongle would be delayed :rofl:

Busy playing with Smart Meters at the moment, will let you know if/when their dongle arrives.

I have received a 2nd standing desk (from work) however, which I believe uses a different brand controller. I might take a look to see if the controls are compatible with each other, as that could be useful to know too.

1 Like

Hey! I got this working for myself!

Unfortunately I forgot to take a picture of the inside before I screwed it to the desk - but it looks the same as yours in there. I made holes in a Jiffy Box instead of 3D printing the enclosure, and it fits nicely.

I tested it with your config and it works great!

Thanks again for your (and ssieb’s) dedication and for sharing how you did it!

1 Like

That’s great!

I’ll share version 2 in a little bit.

I intercept and pass-through at the jst connector and am designing a second control panel to sit alongside the factory one!

More details later…

1 Like