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

Does anyone know which standing desks are compatible? I have a workrite desk with a similar rj45 connector, so I would love to do this mod!

Did you read the first post?

1 Like

I’ve had good success using an RJ12 connection with my Omnidesk.

One quirk I discovered: the desk goes to sleep roughly 5 seconds after the last height message. If you send a command after this timeout, it gets ignored—so you’d need to send it twice to get a response.

To work around this, I’ve updated this on a fork of @Rocka84’s code to automatically send a ā€œstopā€ message first if more than 4.5 seconds have passed since the last received message. This wakes the desk before sending any actual command.

I also noticed that near the physical limits, the desk can sometimes report inaccurate height values. For example, at the lowest position (63.7 cm), it occasionally returns something like 51.2 cm. So I’ve added logic to set any out-of-bounds readings to the nearest physical limit. The display seems to have similar logic as it shows the correct height (63.7cm) also.

I’m also interested to know how the bluetooth app is saving settings to the desk (i.e. custom heights and positions). I know it talks direct to the display as the controller has no bluetooth from what I can see? So I assume this is done via UART on the RJ45, but can’t see any TX pins in the original image. I have a logic analyser so would be great to find some more commands. If anyone has an idea of what pin the display is using for TX that would be great to know.

On the RJ45 port there are no uart messages from the control panel to the controller (only the other way).

Commands are sent via combining high/low on 4 wires. Take a look here around ā€œknown commandsā€.

On the rj12 port there is uart wires for both directions.

Hello, Let me start by thanking you and everyone involved for this awesome work! I tried to hold of before posting and I got pretty far, but alas I’m stuck.

I have a Uplift V1 desk with both an RJ12 and RJ45 connector. I picked up a WaveShare ESP32-S3-Zero-M and the appropriate dupont cables. Been a long time since I soldered and where I am, I can’t open the windows.

Initially I conflated which library to use with which diagram but I’ve got that also sorted using your main solution diagram and the default GitHub - ssieb/esphome_components: My collection of components for esphome firmware.

I’ve got the board powered by ethernet with no issue, and am not doing passthrough - for now I don’t see a need for it.

My issue lies in getting the current heigh back, no matter which combination I try, I don’t seem to get any information back.

I’ve tried using the TX/RX pins, using GPIO09 and GPIO08, and other combinations I’m too out of it to remember now. I currently have what would be your Blue ethernet position #4 connected to GPIO8 - though I’ve tried flipping 08 and 09 just to see.

The up/down/stop are working marvelously, is there a glaring mistake in the below, or is that a limitation of V1 Uplift?

esphome:
  name: desk-controller # change this!
  friendly_name: Desk Controller # change this!
  on_boot:
    priority: -100.0
    then:
    #Request a desk height update after boot.
      - delay: 5s
      - switch.turn_on: wake_desk_and_get_height
    
esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: arduino

# Enable Home Assistant API
api:
  encryption:
    key: !secret ha_encrypt

ota:
  - platform: esphome
    password: !secret esp_home

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Deskcontroller Fallback Hotspot"
    password: !secret fb_pass

captive_portal:

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/esphome_components
      ref: desky
    components: [ desky ]

uart:
  - id: desk_uart
    baud_rate: 9600
    #rx_pin: GPIO09
    tx_pin: GPIO09 #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: 25.3
    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"
    optimistic: true
    unit_of_measurement: cm
    #Limit the range
    min_value: 42.5
    max_value: 44.9
    step: 0.1
    restore_value: true
    initial_value: 43.9
    
#Sitting Height Chair - Set a sitting height. This is independant of what you've set via the control panel.
  - platform: template
    id: desky_sitting_height_chair
    name: "Desky Sitting Height Chair"
    optimistic: true
    unit_of_measurement: cm
    #Limit the range
    min_value: 26.5
    max_value: 27.8
    step: 0.1
    restore_value: true
    initial_value: 27
      
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: GPIO08
      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: GPIO12
      # 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: GPIO13
      # 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

Edit Here is a current wiring setup:

Thank you again, hoping to get automating soon!

uart:
  - id: desk_uart
    baud_rate: 9600
    rx_pin: GPIO09 # try some other pins too.
    debug:
      direction: RX
      dummy_receiver: true
      after:
        bytes: 4
      sequence:     
        - lambda: UARTDebug::log_int(direction, bytes, ',');

As a first step to debug, you should remove/comment out all of your config except for the very bare bones needed for uart and just focus on trying to recieve some uart debug messages on the wire that transmits height messages from the controller to the display.

This might be a brown wire as per diagram. Initially you may need to move the desk to trigger them to be sent. Usually debugging this step is just something simple with wiring, gpios or config.

If you find some uart messages in the logs then post them.

Hi, I have the same controller (jarvis desk), but mine does not work with the standard wiring (height is not read) - what wiring diagram did you use?

The post above yours may help troubleshoot.

Has anyone tried making HA talk to the new Desky bluetooth controller directly? I have a Bluetooth dongle used for Bluetooth integration in HA and I can see Desky bluetooth device in the advertisements.

Would be great to do the same what the phone app can do as it will not require any additional hardware.