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

Right I’m not very good with Discord.

I think you want to first join the ESPHome Discord Server (If you haven’t already).

Then maybe try this link to the thread:

If you can’t find/access the thread via that link, just search for “Desky” under the ‘general-support’ channel.

I’ll see if I can upload the case to Thingiverse now. Never done that…

I’ve uploaded the enclosure to Thingiverse and linked to it in the main solution post.

I can’t see the preview of it yet. Maybe the cloud is still processing the preview? Let me know if you have issues with access or using it. First time I’ve published a Thing.

This thread is a fascinating one, as I believe I have the same controller and dongle, but mine came from a company in Australia called Zen Space Desks that rebranded the units (which added to the challenge).
Anyway, I happened to have a Raspberry Pi Zero 2 W under my desk for the UPS and found a super-helpful guy on GitHub who had the same frustrations as me.
I’ve hooked mine up to my Teams presense, and have the full write-up here: Automatically raise your desk when joining a Microsoft Teams call or meeting – Loryan Strant, Microsoft 365 MVP
However, now that I see this approach using ESP32, I’m tempted to switch.

Nice one!

So your approach sends commands to the Bluetooth dongle?

I was pretty keen to do what I think the author was originally planning which is to replace the Bluetooth dongle with an ESPHome one but there was no way to determine/sniff the messages between the actual dongle and controller pins without having a dongle.

You might have seen what I learnt here.

IIRC from my initial desk research Zen Space use Jiecang hardware as you’ve suggested…

Yeah that’s exactly what ine does.
I actually reached out to the manufacturer and spend quite a bit of time trying to figure out options, until I stumbled across the GitHub repo (linked in my blog post) where the guy has already done the hard yards to sniff out the commands.
He’s just added some functionality to read the height of the desk too.

1 Like

This is great stuff! I’m the guy DeLorean mentioned who reverse engineered parts of the bluetooth functionality on https://github.com/C-Lock/desk_control.

It’s worth mentioning here, that in the US at least, this desk was the Uplift Sit-to-stand desk sold by Staples. Hopefully that info will help other clever folks find this thread.

My initial thought was to use a raspberry pi as a ‘listener’ for the commands between the bluetooth dongle and the desk controller via the GPIO pins and some fancy (hacky) ethernet wiring. I only did it with bluetooth because a friend pointed out (rightfully so), that it was a great excuse to learn something about bluetooth.

On a side note, I guess that means I should probably finish cleaning up the code and remove some bugs…

3 Likes

Hey yeah I was similary curious about learning bluetooth. Nice one.

I suspect that any desks that use Jiecang contollers should be compatible with the ESPHome wifi dongle approach primarily used in this thread. Might build up a list and maybe add it to the OP. Here’s a rough start. If people build a wifi dongle and confirm it works I’ll indicate so.

“Confirmed working” means someone built and tested the ESPHome wifi Dongle.

Jiecang OEM based desks:

  1. Desky | Confirmed working
  2. Assmann | Confirmed working
  3. Jarvis | This article indicates they use Jiecang
  4. Uplift | This article indicates they use Jiecang (and others have confirmed too).
  5. Omnidesk | Suggested here
  6. Zen Space | Suggested here (and in this thread)

The Uplift came with the jcp35n-blt, which is by Jiecang.

1 Like

Hey if there was any way you could capture the up and down UART commands on the Bluetooth port if you have time, I think that could potentially be quite useful.

I’m not sure, but I think that might be a matter of hooking up the MT and MR to ESPHome rx/tx and watching for the messages using the debug.

https://fccid.io/2ANKDJCP35NBLT/Internal-Photos/Internal-Photos-3727739

I’m guessing the protocol that is sent from the app to the dongle is different than between the dongle and the controller? I don’t know much about these things.

This would enable people to build a WiFi dongle that goes into the Bluetooth port, rather than a pass-through dongle on the RJ45 port.

Debug settings are up here (for rx)

And you still cannot fathom how appreciative I am of it.
I am standing sooooooooooo much more during the day, which is much better for my knees by the end of it, as well as improving my concentration - as I tend to step away from the desk so am not tempted to use the keyboard & mouse during calls.

1 Like

I was originally going to implement an up/down schedule (maybe 1hr sitting then 20min standing). But I’ve decided to trial “push-up mode”. After 1hr of sitting the desk will raise and you stand until you want to sit.

For me I “forget to stand until it’s probably a little late”.

I should have some details of my almost finished control panel V2 in the next week.

Awesome. I originally wanted it to be based on an hour of sitting as well, but then didn’t want it to be in the middle of typing or focusing.
For me, I find standing is most effective when I want to be creative (ie. writing/thinking) as I can easily pace around, as well as in meetings as it helps me pay attention (I have ADHD, so distraction is a problem).

1 Like

That’s the great thing about being able to customise! Set it up for what works for you!

1 Like

Option #2: Custom Control Panel
(Will refine this post and add detail)

Summary:

  • By passing-through at the “JST Control Panel Connector” (PH 2.0mm 8Pin) rather than the RJ45, it’s a bit easier to locate the ESP “within reach”.
  • Then you can add all kinds of sensor and interface options (I added screens, LEDs, a buzzer, a PIR, a ToF, and an Endstop for my keyboard drawer). I originally had a lux sensor but broke it and decided to just swap it out with the PIR.

Key features:

  • Presence & Sitting detection (multi-pronged) using PIR, ToF, desk height, keyboard drawer position, BLE smart band detection.
  • One-press button toggles sit/stand.
  • Implemented a “push-up” mode. Desk moves to standing after x minutes of sitting.
  • Display time until you need to stand and time in current position
  • Other button: Long press to toggle activating push-up mode. Short press extends time until standing if time nearly up.

Cracks me up that even though the control panel it is “much smarter”, it looks pretty vintage;)

Parts list:

  • An ESP32 (you’ll need lots of pins): I decided to use a LILYGO® TTGO T7 Mini32 V1.5 for this, but I’m sure other decent ESP32’s which fits in the enclosure would be fine. I wouldn’t go too cheap. You could take a look here.
  • 2 x LED’s (recommend two different colours of your choice). I used these ones. They have a built in resistor.
  • 2 x push buttons: I got these ones. I think they’re ok. I have occasional reliability issues though. Not sure if it’s related to quality of buttons or something else.
  • 1 x RTTL buzzer: I’ve been using these ones.
  • 2 x screens: These SSD1306’s have been fine.
  • A ToF sensor: These VL53L0X’s have been fine.
  • A motion sensor: I bought a few different types of these to try. Can’t recall which one I used. Can find out if needed.
  • If you want to throw in a light sensor, I’d go with a BH1750
  • Wire, solder, duponts etc…

Here’s a copy of the enclosure (updated 2024-01-25)
https://www.printables.com/model/737413-desky-custom-control-panel-option-2

It’s ok but could benefit from further tweaking. In hindsight I think just using two RJ45 breakouts and passing through like this might be neater. https://www.tindie.com/products/tjhorner/wifi-standing-desk-controller/

Config:
Hmmm… too big to upload.
I’ve just dumped a snapshot here.

2 Likes

File this under things I didn’t know I needed! I’ve been thinking about making my Uplift desk smart just by tapping into the existing controls to nudge me to stand more often but this panel opens up so many more options. Very interested to hear more and see a parts list when you have time. Was this a custom PCB?

1 Like

I’ll add the parts list and config in the next few days for you.

It’s just an esp32.

It’s been working quite well.

I’ve added a parts list, my config and a link to the enclosure on Thingiverse to the main post . Cheers.

1 Like

Thank you guys for all the hard work. I adjusted the yaml file to treat the desk as cover that provides the following:

  • Standing position configuration
  • Sitting position configuration
  • Cover with standing/sitting actions and adjustable positions
substitutions:
  descriptor: 'Office Desk'
  unit_of_measurement: 'in'
  min_height: '30.5'
  max_height: '56.1'
  default_standing_height: '35.5'
  stopping_distance: '1'

esphome:
  name: desk-controller
  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

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: desk-controller
    password: !secret wifi_ap_password

api:
ota:

logger:

external_components:
  - source:
      type: git
      url: https://github.com/ssieb/custom_components
    components: [ desky ]

uart:
  - id: desk_uart
    baud_rate: 9600
    rx_pin: 1

desky:
  id: desk_controller
  up:    
    number: 4 #D2
    inverted: true 
  down:  
    number: 5 #D1
    inverted: true
  request:
    number: 14 #D6
    inverted: true
  stopping_distance: ${stopping_distance}
  timeout: 15s
  height:
    id: desk_height
    accuracy_decimals: 1
    unit_of_measurement: ${unit_of_measurement}
    filters:
    - delta: 0.05
    - throttle: 200ms
    - multiply: 0.1
cover:
  - platform: template
    name: ${descriptor}
    device_class: blind
    icon: mdi:desk
    lambda: |-
      if (id(desk_height).state >= id(desk_standing_height).state) {
        return COVER_OPEN;
      } else {
        return COVER_CLOSED;
      }
    open_action:
      - lambda: id(desk_controller).move_to(id(desk_standing_height).state * 10);  
    close_action:
      - lambda: id(desk_controller).move_to(id(desk_sitting_height).state * 10);  
    stop_action:
      - lambda: id(desk_controller).stop();
    tilt_lambda: |-
        return (id(desk_height).state - ${min_height}) / (${max_height} - ${min_height});
    tilt_action:
      - lambda: id(desk_controller).move_to(((tilt * (${max_height} - ${min_height})) + ${min_height}) * 10);  

number:
  - platform: template
    id: desk_sitting_height
    name: ${descriptor} Sitting Height
    optimistic: true
    unit_of_measurement: ${unit_of_measurement}
    min_value: ${min_height}
    max_value: ${default_standing_height}
    step: 0.1
    restore_value: true
    initial_value: ${min_height}
    mode: box
    icon: mdi:arrow-down
    
  - platform: template
    id: desk_standing_height
    name: ${descriptor} Standing Height
    optimistic: true
    unit_of_measurement: ${unit_of_measurement}
    min_value: ${default_standing_height}
    max_value: ${max_height}
    step: 0.1
    restore_value: true
    initial_value: ${default_standing_height}
    mode: box
    icon: mdi:arrow-up
2 Likes

Nice one. Thanks for sharing that back.

I was thinking about something similar but wasn’t sure how good a fit the mapping to a cover would work. I think covers like a % open/closed? I just skimmed your config and will look closer.

Keen you hear if that works well for you.

Do you have a Desky desk or something else?

Cheers…

With the way the cover is configured, there is an open and close action that will go to the configured standing and sitting positions. There is also the ability to give a percentage a position. For example a 100% is the maximum height the desk could go to. My standing position happens to be around 60%.

I am using this with an uplift desk.

1 Like