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

Thanks for the reply. After browsing that list, it appears to be the JCB35NH2: Control Box JCB35NH2 - JIECANG

I’m only basing that off of the fact it has the same ports, looks to be the same size and is also 400w.

1 Like

So there’s a decent chance it should work with this project. You just need to keep an eye out for the “secondary or alternative protocol” mentioned in this thread (which is not yet supported).

1 Like

Just wanted to report back my findings. I got the desk working with Option #1 in the original post! I changed the units to inches and also changed my limits to match. Still tweaking with it slightly but it moves up and down and reports height in Home Assistant!

Thanks again for the help!

1 Like

Couple of pictures of my install if anyone is interested.




2 Likes

Glad to hear. Thanks for reporting back!
Looks like a neat build.

1 Like

Thanks! I had one last question. I’m actually using the “Desk Is Moving” state to control a zigbee plug that energizes/de-energizes an electromagnet that is mounted to my desk that attaches to a steel plate I mounted to my wall. Well, the zigbee plug is too slow to turn on/off with the “Desk Is Moving” state.

Do you think I could use an output on the D1 Mini that fires when that “Desk Is Moving” state is true?

Edit: disregard, I figured out how to add the output. Had to just play with it some more :slight_smile: I’m still fairly new to esphome in general. Super excited for this!

1 Like

You’ve got me curious about this!

Would you mind sharing the use case?

Yeah definitely. So, I am a big proponent of having a rigid benchtop and desktop, so I typically just bolt my desks to the wall with a big L bracket. Well, you obviously can’t do that with a standing desk, so I bought a piece of 6" x 30" steel and mounted it to the wall behind my desk and bought an electromagnet from amazon that is meant to hold doors shut. I printed a mount to hold the magnet to the desk and it has like a 350lb rating.

I’m currently using a zigbee plug with a 12v power supply plugged into it to control the electromagnet. Ideally, I’d like to control this zigbee plug with the “desk is moving” bit in home assistant, however there is too much delay between when I press the down button, and the zigbee plug turns off. It’s only like a second or two, but that’s enough to bind up the desk and cause the magnet to keep holding.

This is where my question came in. I plan on controlling the magnet with an output from the D1 to a relay that allows the 12v to go to the magnet instead. I think this will give a much more instant response than waiting for the zigbee plug. The magnet takes like 1-2 seconds to energize, however it de-energizes very quickly, allowing the desk to move.

Here are some pictures to get a better idea, and this is the electromagnet that I am using (I took it out of its case since that just added bulk).



Ah I see. So it is an anti-wobble device?

Yep. Albeit, maybe a little over-engineered or overkill, but that’s kind of why we’re all here, right? haha

2 Likes

You might get a laugh out of one of my lockdown projects then. It was a bit of failure in the end but was fun to build.

Oh my goodness, this is amazing! Yeah, not going to mention “overkill” again, I now know I’m in the right place haha.

1 Like

Hello @jcastro. Do you have the big fully controller with display or only the small one?
Could you maybe DM me your ESPHome config? I cant get the logging working.
Also my display isnt working anymore on the fully controller when my passthrough is connected. @Mahko_Mahko do you maybe have an idea about this?

Controller and ESP32

The first one is my used controller. This is my used ESP32

Config

esphome:
  name: standing-desk
  friendly_name: Standing Desk
  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: esp32dev
  framework:
    type: arduino

# Enable logging
logger:
  level: VERY_VERBOSE
# Enable Home Assistant API
api:
  encryption:
    key: "lBXwa0ZuqNLMwW4rHZC0PhX7yCSeXnKencdECSKA1wY="

ota:
  password: "359fa6d122acb1d2dabc5366276edc66"

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

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Standing-Desk Fallback Hotspot"
    password: "gi4UyEI3xG5D"

captive_portal:


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
    ##You can uncomment the debug section below to see UART messages.
    debug:
      direction: BOTH
      dummy_receiver: true
      after:
        bytes: 9
      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: GPIO18
      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: GPIO21
      # 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: GPIO22
      # 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
  


 

Logs so far - Cant’t get uart logs

[15:03:52][V][mdns:117]:   Services:
[15:03:52][V][mdns:119]:   - _esphomelib, _tcp, 6053
[15:03:52][V][mdns:121]:     TXT: friendly_name = Standing Desk
[15:03:52][V][mdns:121]:     TXT: version = 2024.4.2
[15:03:52][V][mdns:121]:     TXT: mac = 409151ab9734
[15:03:52][V][mdns:121]:     TXT: platform = ESP32
[15:03:52][V][mdns:121]:     TXT: board = esp32dev
[15:03:52][V][mdns:121]:     TXT: api_encryption = Noise_NNpsk0_25519_ChaChaPoly_SHA256
[15:03:52][VV][scheduler:226]: Running interval 'update' with interval=60000 last_execution=768395 (now=828396)
[15:03:54][VV][scheduler:226]: Running interval '' with interval=60000 last_execution=772092 (now=832092)
[15:03:54][VV][scheduler:226]: Running interval 'update' with interval=60000 last_execution=772340 (now=832345)
[15:03:55][VV][api.service:602]: on_ping_request: PingRequest {}
[15:03:55][VV][api.service:043]: send_ping_response: PingResponse {}
[15:04:26][VV][api.service:690]: on_switch_command_request: SwitchCommandRequest {
  key: 529781321
  state: YES
}
[15:04:26][D][switch:012]: 'Raise Desk' Turning ON.
[15:04:26][D][switch:055]: 'Raise Desk': Sending state ON
[15:04:27][VV][scheduler:032]: set_timeout(name='', timeout=15000)
[15:04:27][VV][api.service:156]: send_switch_state_response: SwitchStateResponse {
  key: 529781321
  state: YES
}
[15:04:27][VV][api.service:690]: on_switch_command_request: SwitchCommandRequest {
  key: 529781321
  state: NO
}
[15:04:27][D][switch:016]: 'Raise Desk' Turning OFF.
[15:04:27][D][switch:055]: 'Raise Desk': Sending state OFF
[15:04:27][VV][api.service:156]: send_switch_state_response: SwitchStateResponse {
  key: 529781321
  state: NO
}
[15:04:31][VV][api.service:690]: on_switch_command_request: SwitchCommandRequest {
  key: 2153922382
  state: YES
}
[15:04:31][D][switch:012]: 'Request Desk Height' Turning ON.
[15:04:31][D][switch:055]: 'Request Desk Height': Sending state ON
[15:04:31][VV][scheduler:032]: set_timeout(name='', timeout=100)
[15:04:31][VV][api.service:156]: send_switch_state_response: SwitchStateResponse {
  key: 2153922382
  state: YES
}
[15:04:31][VV][scheduler:226]: Running timeout '' with interval=100 last_execution=869049 (now=869154)
[15:04:31][D][switch:016]: 'Request Desk Height' Turning OFF.
[15:04:31][D][switch:055]: 'Request Desk Height': Sending state OFF
[15:04:31][VV][api.service:156]: send_switch_state_response: SwitchStateResponse {
  key: 2153922382
  state: NO
}
[15:04:37][VV][scheduler:226]: Running interval 'update' with interval=60000 last_execution=814817 (now=874818)
[15:04:38][VV][scheduler:226]: Running interval 'update' with interval=60000 last_execution=816082 (now=876090)
[15:04:41][VV][scheduler:226]: Running timeout '' with interval=15000 last_execution=864543 (now=879544)
[15:04:41][D][switch:016]: 'Raise Desk' Turning OFF.

HA Details
Up and down is working.

One last thing i noticed:
The desk usually is showing the height in inch not cm or mm when the display is working.

I also opend my controller board and checked my RJ45 layout. It matched the config from #Option 1

UPDATE:

I had to solder the TX pin of the controller to GPIO17 instead of GPIO3. No I’m getting the uart logs. I still facing the same issue as @jcastro. When looking at my logs the 5th and the 6th byte caltulate my desk height. Therefore i still cant see the height in HA. I managed to switch from inch to cm in the controllers settings.

@Mahko_Mahko @ssieb do you have any further tips how to get the height to work?

LOGS:

[20:43:51][D][switch:012]: 'Request Desk Height' Turning ON.
[20:43:51][D][switch:055]: 'Request Desk Height': Sending state ON
[20:43:51][VV][scheduler:032]: set_timeout(name='', timeout=100)
[20:43:51][VV][api.service:156]: send_switch_state_response: SwitchStateResponse {
  key: 2153922382
  state: YES
}
[20:43:51][D][uart_debug:176]: <<< 242,242,1,3,2,232,15,253,126
[20:43:51][VV][scheduler:226]: Running timeout '' with interval=100 last_execution=12504 (now=12610)
[20:43:51][D][switch:016]: 'Request Desk Height' Turning OFF.
[20:43:51][D][switch:055]: 'Request Desk Height': Sending state OFF
[20:43:51][VV][api.service:156]: send_switch_state_response: SwitchStateResponse {
  key: 2153922382
  state: NO
}
[20:43:51][D][uart_debug:176]: <<< 242,242,1,3,2,232,15,253,126
[20:43:52][D][uart_debug:176]: <<< 242,242,1,3,2,232,15,253,126
[20:43:52][D][uart_debug:176]: <<< 242,242,1,3,2,232,15,253,126
[20:43:52][D][uart_debug:176]: <<< 242,242,1,3,2,232,15,253,126
[20:43:52][D][uart_debug:176]: <<< 242,242,1,3,2,232,15,253,126
[20:43:52][D][uart_debug:176]: <<< 242,242,1,3,2,232,15,253,126
[20:43:53][D][uart_debug:176]: <<< 242,242,1,3,2,232,15,253,126
[20:43:53][D][uart_debug:176]: <<< 242,242,1,3,2,232,15,253,126
[20:43:53][D][uart_debug:176]: <<< 242,242,1,3,2,232,15,253,126
[20:43:53][D][uart_debug:176]: <<< 242,242,1,3,2,232,15,253,126
[20:43:53][D][uart_debug:176]: <<< 242,242,1,3,2,232,15,253,126
[20:43:54][D][uart_debug:176]: <<< 242,242,1,3,2,232,15,253,126

CONFIG:

uart:
  - id: desk_uart
    baud_rate: 9600
    rx_pin: GPIO17
    ##You can uncomment the debug section below to see UART messages.
    debug:
      dummy_receiver: true
      after:
        bytes: 9
      sequence:     
        - lambda: UARTDebug::log_int(direction, bytes, ',');

hi! I removed it completely a long time ago because it was never implemented, as a function to control the desk, so I gave up

1 Like

Interesting. So you’re the second person in addition to @jcastro who has a desk that uses a slightly different protocol.

The feature request for supporting that has been open for some time.

What I’d encourage you both to do is make a comment on the issue to help flag to @ssieb that there is still demand for the enhancement.

You could also take a look at the Upsy Desky project and try to figure out if your protocol is already supported.

If you are willing to tinker in cpp I suspect it would be relatively small adjustments to this code section to just read bytes in two different positions.

Thanks for your response. I will make a comment tomorrow. I also will check the c++ config. Maybe I can figure it out by myself. Not really into c++ but we’ll see. :innocent:

1 Like

ssieb is active on the development of support for this alternative protocol now (beta has been released), so if you still have some interest and the hardware, more testers would be helpful.

1 Like

I can confirm @ssieb work. I tried his solution with my Fully Jarvis Desk.

Everything works like a charm. @jcastro you could also try it now. Should also work with your desk.

How to update the repository:

Clean the Build folder of your ESP32 and reinstall the yaml file. This way the repository should update. You also could change your config in the following way and reinstall:

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 ]
    refresh: 0s

Thanks again to the nice work of @ssieb and @Mahko_Mahko.

1 Like

@hraschan would you mind sharing your whole config? I don’t have mine anymore. I’m using ESP8266 so I will just change the pin numbers. Thanks

Please keep in mind that i also configured my 4 memory buttons. As i remember you got the small controller. Therefor you don’t need them. Also make sure your uart config is right. I also changed that. Because I needed a different pin there as well.

esphome:
  name: standing-desk
  friendly_name: Standing Desk
  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: esp32dev
  framework:
    type: arduino

# Enable logging
logger:
  level: VERY_VERBOSE
  # baud_rate: 0 #disable logging over uart
# Enable Home Assistant API
api:
  encryption:
    key: "lBXwa0ZuqNLMwW4rHZC0PhX7yCSeXnKencdECSKA1wY="

ota:
  password: "359fa6d122acb1d2dabc5366276edc66"

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

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: GPIO17
    ##You can uncomment the debug section below to see UART messages.
    debug:
      dummy_receiver: true
      after:
        bytes: 9
      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
substitutions:
  #Use your own ESP pin values
  desky_request_height_pin: GPIO18 #Request desk height | white wire  
  desky_purple_pin: GPIO16 #purple wire  
  desky_down_pin: GPIO22 #Move desk down | yellow wire  
  desky_up_pin: GPIO21  #Move desk up | green wire  

output:
  - platform: gpio
    pin: ${desky_up_pin}
    id: up_green_wire
    inverted: true
  - platform: gpio
    pin: ${desky_down_pin}
    id: down_yellow_wire
    inverted: true
  - platform: gpio
    pin: ${desky_purple_pin}
    id: purple_wire
    inverted: true

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: ${desky_request_height_pin}
      inverted: true
    on_turn_on:
    - delay: 100ms
    - switch.turn_off: wake_desk_and_get_height

#Raise the desk 
  - platform: output
    output: up_green_wire
    id: raise_desk
    name: "Raise Desk"    
    on_turn_on:
    #Auto off after 15s just in case
    - delay: 15s
    - switch.turn_off: raise_desk
#Lower the desk 
  - platform: output
    output: down_yellow_wire
    id: lower_desk
    name: "Lower Desk" 
    on_turn_on:
   #Auto off after 15s just in case
    - delay: 15s
    - switch.turn_off: lower_desk

button:
  # Combination Buttons
  - platform: template
    name: "Memory 1"
    id: button_1
    on_press:
      then:
        - output.turn_on: up_green_wire
        - output.turn_on: down_yellow_wire
        - delay: 300ms
        - output.turn_off: down_yellow_wire
        - output.turn_off: up_green_wire
  - platform: output
    output: purple_wire
    name: "Memory 2"
    id: button_2
    duration: 300ms
  - platform: template
    name: "Memory 3"
    id: button_3
    on_press:
      then:
        - output.turn_on: purple_wire
        - output.turn_on: down_yellow_wire
        - delay: 300ms
        - output.turn_off: down_yellow_wire
        - output.turn_off: purple_wire
  - platform: template
    name: "Memory 4"
    id: button_4
    on_press:
      then:
        - output.turn_on: purple_wire
        - output.turn_on: up_green_wire
        - delay: 300ms
        - output.turn_off: up_green_wire
        - output.turn_off: purple_wire
#Stop movement 
  - platform: template
    name: Stop Desk
    id: desky_stop_desk
    on_press:
      then:
        - switch.turn_off: raise_desk
        - switch.turn_off: lower_desk

      

  


1 Like