Maidesite Standing Desk with ESPHome

My findings getting this desk working with ESPHome

4 Likes

For anyone interested, my test code so far is here GitHub - shades66/Maidesite-standing-desk: My experimentations with connecting a Maidesite PRO 2 standing desk controller to HomeAssist

I was following another great thread on here around how to integrate with HA/ESPHome by tapping into the control & serial lines between the controller & handset but when I received my standing desk it looks like Maidesite changed the design so instead of a separate control box & handset everything is now contained within the handset itself. While I suspect a lot of what others have found would be do-able on this new handset it could easily void any warranties/guarantees pretty quickly I decided to see what could be done via the RJ12 socket which this machine does have. It has no mention Jiecang anywhere on the hardware/instructions I started playing with some information found off that thread and pretty quickly got the basics working. The hardest part was trying to get information to make the desk move to a specific position but eventually found someone had created a spreadsheet with a ton of useful information which suggests the controller is probably made by Jiecang or based on their design so is possibly usable by other brands that have an RJ12 connector.

So far working is

  • Button to trigger any of the 4 presets
  • Button to move UP/DOWN
  • Slider to move direct to a height
  • Get current settings for height & presets

Todo

  • Tidy up code (remove test stuff)
  • Make it retrieve the current height automatically (you need to press the test button at the start)
  • Add buttons to create presets based on current height
  • Look into automations to automatically lower after alarms/no-one at desk

hope it is of use to someone else with this desk.

3 Likes

Great work @Shades66.

I am planing to automate my Maidesite Desk, just waiting for the RJ12 cable to arrive.

By any chance could you add a photo / pic with the esp wiring. The devider for the TX connection is confusing me a bit.

Thanks a lot.

Edit: The cable arrived, but the colors are different. I think I have managed to work out the connections.
I have set up the eps32. Now when I trigger the TEST button, the desk control pannel lights up and the following is printed to the console. The rest of the sensors are unavailable.

It seem I’ve got some data send to the desk, but looks like nothing is getting from the desk to the ESP32.

[21:49:35][D][uart_debug:176]: >>> 241,241,7,0,7,126,241,241,8
[21:49:35][D][uart_debug:176]: >>> 0,8,126,241,241,9,0,9,126
[21:49:35][D][uart_debug:176]: >>> 241,241,12,0,12,126,241,241,14
[21:49:35][W][component:204]: Component api took a long time for an operation (0.05 s).
[21:49:35][W][component:205]: Components should block for at most 20-30ms.
[21:49:35][D][uart_debug:176]: >>> 0,14,12

Edit 2:

Got there at the end. Works well. Can’t wait to automate my daily standing routine :slight_smile:

Thanks again for your work!!!

1 Like

Hey, sorry I didn’t see anyone had responded to this, Glad to hear you got it working :slight_smile:

I’ll add an image of the wiring to make it easier to identify the correct colours at some point over the weekend

anyone else wanting to know the circuit diagram I used the circuit from this page (just the resistors part into the ESP’s RX pin) Arduino Uno serial communication with ESP32 using voltage divider - #2 by groundFungus - Project Guidance - Arduino Forum

1 Like

Nice work, i’ve got my cable and begin my work these days… thanks for your effort! Will tell you, if i was successful

Hi Mark,

I’m a bit lost as unfortunately not as technical as I once was… do you have a photo of your wiring etc please if possible linked to the ESP 32?

Do I flash desk.h onto the board and load dskcontrol.yaml into my configuration on Home Assistant?

Thanks

Richard

Hi guys!
I’m following the GitHub project to integrate my Maidesite desk as well.
Code on the ESP seems to be OK but I’m stuck at the very same first edit of @tomino

[21:18:05][D][button:010]: 'Desk test' Pressed.
[21:18:05][D][main:495]: TEST Pressed
[21:18:05][D][uart_debug:176]: >>> 241,241,7,0,7,126,241,241,8
[21:18:05][D][uart_debug:176]: >>> 0,8,126,241,241,9,0,9,126
[21:18:05][D][uart_debug:176]: >>> 241,241,12,0,12,126,241,241,14
[21:18:05][D][uart_debug:176]: >>> 0,14,126

No infos from the desk and as far as I can tell no other button are functioning. Any clues are welcome. What did I do wrong?

Hoping to read from you, as I revived this aging topic…

My bad!…
I was missing the home assistant’s entity to enable desk movement.
All’s up&running! Big up for the awesome work.

1 Like

Hey, how did you manage to make it work in the end?
I got to the point where I can send the signals to the desk and make it move up/down, but I’m not getting any data from the desk back (current height, M1-4 heights). Do you happen to have a photo of your setup?

Hey, my problem was with the connections to uart. I had them mixed up.

Hi. I’m about to dive into your solution.
Has there been any progress on the remaining todo list?

I have a hard time to get it running.

I have a nodemcu esp-c3-32s-kit a151, the 5V from the RJ Connector is enough to power it. (Still tried the USB power to make sure)

But I had trouble finding the correct TX and RX pins for the esphome config. Turns out, I could not use the uart0 pins (U0RX U0TX). Instead I had to use others.

Receiving data now works, I get the memory profiles and the current height.
Sending data does not work, except the “Desk test” to trigger re-receiving the data.
But all commands dont do anything. Changed to different pins made no difference.

I also redid the whole connection, first I had a really long cable. Also I can beep it through with my multimeter. So I find it a bit strange that receiving works, but sending (that’s just a plain connection) does not.

Any ideas?

Added: my working wiring (maybe you need 5V and GND from USB - esp32-c3-devkitm-1 got enough power over RJ14, esp32dev (wroom rev1) did not)


From top to bottom:
purple GND
green TX
blue 5V
white RX

I have a RJ14, that works too(same connector, but only 4 pins in use)

1 Like

My bad!…
I was missing the home assistant’s entity to enable desk movement.

I finally found out what was the problem. This. I didn’t understood what HobbitBen ment. It took me very long to figure it out myself.
Also the documentation is very unclear about this “feature”.
I also expected, that when I manually turn on that switch, it should stay on.

For anyone else that stumbles over this problem:

There is a home assistant entitiy binary_sensor.presence that is imported into ESPhome, and it only works if that is “on”.

  • So either update the ESPhome config to reflect that binary sensor name, if you have any presence detection. (under text_sensor:)
  • Or create a dummy binary_sensor.presence that is always on.
  • Or disable the check in the ESPhome config:
switch:
  - platform: template
    name: "Desk Enable"
...
        return true;
      } else {
        return true; # <--- instead of false
      }
...

Can someone maybe post a picture of the final set up.
I have a MAIDeSITe T2 Pro desk which I understand is the same as what @Shades66 has.

My understanding is that to get the control of the desk to HomeAssistant one needs a ESP board connected via RJ12 to the second (free) port to the motor controller (see picture at the bottom) and a usb power cable to provide power to the ESP.

Then deskcontrol.yaml and desk.h are used with ESPHome and that should be all.

Am I wrong?

No worries. With some level of careful reading it worked. Cudos to @Shades66. Excellent work :smiley:

I suspect that this project will work for the Maidesite desks on the RJ12 port.

I’ve tested it and it works well on my Desky Desk.

The RJ12 dongle is also easier to make than the RJ45 dongle.

Probably you can even get a basic solution with yaml only like this:

Yaml only solution
# You probably won't need the stuff under platformio_options: and framework: , I'm just using a weird board.
esphome:
  name: "jiecang-desk-controller-rj12-c3"
  friendly_name: Desk Controller RJ12 C3 
  comment: Desk Controller for Jiecang Controllers via RJ12 port
  platformio_options: 
    board_build.flash_mode: dio 
  on_boot:
    priority: 0
    then:
      - button.press: cmdFetchHeightValue # Request height on boot.
  
esp32:
  board: esp32-c3-devkitm-1
  framework:
    type: esp-idf
    sdkconfig_options: 
      CONFIG_BT_BLE_42_FEATURES_SUPPORTED: y 
      CONFIG_BT_BLE_50_FEATURES_SUPPORTED: y
      CONFIG_ESP_TASK_WDT_TIMEOUT_S: "10" 
      variant: ESP32C3 # lolin c3 pico pinout |  https://arduino-projekte.info/wp-content/uploads/2023/01/Wemos-Lolin-C3-Pico-Pinout.webp
  
wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    static_ip: 192.168.1.XXX  # I like to set static IPs.
    gateway: 192.168.1.1
    subnet: 255.255.255.0
api:
ota:

logger:
  level: VERBOSE   # Required for uart debug messages.

uart:
  tx_pin: GPIO21 
  rx_pin: GPIO20 
  baud_rate: 9600
  debug:
    direction: BOTH
    dummy_receiver: true
    after:
      delimiter: [0x7E]
      # timeout: 5ms
    sequence:
        # Use mulcmu's method for reading uart without a custome component: https://community.home-assistant.io/t/how-to-uart-read-without-custom-component/491950?u=mahko_mahko
      - lambda: |-
          UARTDebug::log_int(direction, bytes, ',');                // Log the message as int. Good for height message checks.
          UARTDebug::log_hex(direction, bytes, ',');                // Log the message in hex. Good for checking against protocol documentation.
          ESP_LOGD("custom", "Bytes size: %d", bytes.size());       // Logs how many bytes in the message, useful for protocol and message identification.
          if (direction == UART_DIRECTION_RX) 
          {
              if (bytes.size() == 9)                                // Only parse messages with 9 bytes.
              {
                  // Do some validation that it is a height message by checking some bytes.
                  if (bytes[0] == 0xF2 && bytes[1] == 0xF2 && bytes[2] == 0x01 && bytes[8] == 0x7E) 
                  {
                      int height = (bytes[4] * 256) + bytes[5]; 
                      id(desk_height).publish_state(height);
                  }
              }
          }

        

sensor:
  - platform: template
    name: "Desk Height"
    id: desk_height
    update_interval: never
  - platform: uptime
    icon: mdi:sort-clock-descending
    name: Uptime
    id: uptime_sensor
    update_interval: 5s
    accuracy_decimals: 0
    unit_of_measurement: s
    
number:
  - platform: template
    name: "Go To Height cm"
    id: go_to_height_value
    optimistic: true
    min_value: 80.0 
    max_value: 250.0
    step: 0.1

button:
  - platform: uart
    id: "cmdStop"
    name: "Stop"
    data: [0xF1, 0xF1, 0x2B, 0x00, 0x2B, 0x7E]
  
  # Memory Presets  
  - platform: uart
    id: "cmdGotoMemory1"
    name: "Go To Memory 1"
    data: [0xF1, 0xF1, 0x05, 0x00, 0x05, 0x7E]
  - platform: uart
    id: "cmdGotoMemory2"
    name: "Go To Memory 2"
    data: [0xF1, 0xF1, 0x06, 0x00, 0x06, 0x7E]
  - platform: uart
    id: "cmdGotoMemory3"
    name: "Go To Memory 3"
    data: [0xF1, 0xF1, 0x27, 0x00, 0x27, 0x7E]
    
  - platform: template
    name: "Go to specific height X"
    on_press:
      then:
        - uart.write:
            data: !lambda |-
              float height_cm = id(go_to_height_value).state;
              int height_mm = static_cast<int>(height_cm * 10); // Convert cm to mm
              std::vector<uint8_t> bArr(8);
              bArr[0] = 0xF1;
              bArr[1] = 0xF1;
              bArr[2] = 0x1B;
              bArr[3] = 0x02; 
              bArr[4] = static_cast<uint8_t>(height_mm / 256);
              bArr[5] = static_cast<uint8_t>(height_mm % 256);
              bArr[6] = static_cast<uint8_t>((bArr[2] + bArr[3] + bArr[4] + bArr[5]) % 256); // Calculate checksum 
              bArr[7] = 0x7E;
              return bArr;


  - platform: uart
    id: "cmdDown"
    name: "Nudge Down"
    data: [0xF1, 0xF1, 0x02, 0x00, 0x02, 0x7E]
  - platform: uart
    id: "cmdUp"
    name: "Nudge Up"
    data: [0xF1, 0xF1, 0x01, 0x00, 0x01, 0x7E]

  - platform: uart
    id: "cmdMemory1"
    name: "Set Memory 1"
    data: [0xF1, 0xF1, 0x03, 0x00, 0x03, 0x7E]
  - platform: uart
    id: "cmdMemory2"
    name: "Set Memory 2"
    data: [0xF1, 0xF1, 0x04, 0x00, 0x04, 0x7E]
  - platform: uart
    id: "cmdMemory3"
    name: "Set Memory 3"
    data: [0xF1, 0xF1, 0x25, 0x00, 0x25, 0x7E]

  - platform: uart
    id: "cmdFetchHeightValue"
    name: "Fetch Height Value"
    data: [0xF1, 0xF1, 0x07, 0x00, 0x07, 0x7E]


 # If you need anything more than the above you should probably move across to another method / project.

  # - platform: uart
    # id: "cmdFetchAllTime"
    # name: "Fetch All Time"
    # data: [0xF1, 0xF1, 0xAA, 0x00, 0xAA, 0x7E]
  # - platform: uart
    # id: "cmdFetchHeightRange"
    # name: "Fetch Height Range"
    # data: [0xF1, 0xF1, 0x0C, 0x00, 0x0C, 0x7E]
  # - platform: uart
    # id: "cmdFetchHeightValue"
    # name: "Fetch Height Value"
    # data: [0xF1, 0xF1, 0x07, 0x00, 0x07, 0x7E]
  # - platform: uart
    # id: "cmdFetchHighestLowestLimit"
    # name: "Fetch Highest Lowest Limit"
    # data: [0xF1, 0xF1, 0x20, 0x00, 0x20, 0x7E]
  # - platform: uart
    # id: "cmdFetchStandTime"
    # name: "Fetch Stand Time"
    # data: [0xF1, 0xF1, 0xA6, 0x01, 0xA7, 0x7E]
  # - platform: uart
    # id: "cmdPatch"
    # name: "Patch"
    # data: [0xF1, 0xF1, 0xA0, 0x00, 0xA0, 0x7E]

I have tried creating this manual with my Maidesite T2 Pro Plus desk, but I can’t raise or lower it from Home Assistant, although I can read the data.

Has anyone managed to do it with this desk?

Thank you very much for everything.

Hi @tomino,

Great job getting your desk automation to work! I’m also working on automating my Maidesite Desk with an ESP32, but I’m having trouble getting it to communicate properly with the desk.

Could you share more details on how you managed to fix the issue with the desk not sending data back to the ESP32? Did you have to change anything in the wiring, code, or configuration?

Any advice would be greatly appreciated. Thanks for your help!

Hey, I have the same desk, but have the opposite problem.
I can move the desk up and down, but can’t read any of the data.
Maybe we can both help each other out here.

Here’s how I have it connected, but changing the height from Home Assistant works with just connecting to pin 2 and 5 of the RJ12 to GND and TX of the ESP32. (I’m using an ESP32-S3-Zero)


EDIT: I messed up the resistors in the image, the 1K should be 5K and the 5K should be 10K, that’s how I have it at the moment, but it’s not working.

Here’s my yaml: esphome: name: deskcontrol friendly_name: DeskControl includes: - - Pastebin.com
Note that I removed the deskenable switch, as I don’t have a need to disable or enable the desk controls based on presence. I suspect that maybe this is holding you back.
(also, ignore the tx_pin and rx_pin in the yaml, it works the same with leaving it at TX and RX, I was just testing other pins on the ESP)

Could you show me how you have yours wired up, maybe that’ll help me fix my problem too.

Good afternoon!

Thank you so much for your response. Thanks to your guidance, I can now say that I have it configured and working perfectly.

I’m sharing the wiring diagram I used to connect the pins, along with the YAML configuration I implemented. It’s important to note that I used an ESP32 WROOM, which corresponds to an ESP32Dev in ESPHome. Therefore, you’ll need to adjust the board model and pin configuration if you’re using a different ESP device.

If you need any additional information about how I connected it or anything else, feel free to let me know, and I’ll gladly help however I can.

Thank you very much for everything, and best regards!

YAML
esphome:
  name: deskcontrol
  friendly_name: DeskControl
  includes:
    - desk.h  
  on_boot:
    priority: 800
    then:
      - uart.write: [0xf1, 0xf1, 0x07,0x00,0x07,0x7e,0xf1, 0xf1, 0x08,0x00,0x08,0x7e,0xf1, 0xf1, 0x09,0x00,0x09,0x7e,0xf1, 0xf1, 0x0c,0x00,0x0c,0x7e,0xf1, 0xf1, 0x0e,0x00,0x0e,0x7e]

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:


ota:
 platform: esphome

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

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

captive_portal:
    

uart:
  - id: desk_uart
    tx_pin: 17  
    rx_pin: 16
    baud_rate: 9600
    debug:
      direction: BOTH
      after:
        bytes: 9
      sequence:     
        - lambda: UARTDebug::log_int(direction, bytes, ',');

custom_component:
- lambda: |-
    auto my_custom = new MyCustomComponent(id(desk_uart));
    return {my_custom};


sensor:
  - platform: template
    name: "Desk M1 Height"
    id: "deskm1"
    filters:
    - lambda: !lambda |-
        if (x <1 ) return {};
        return x/10;
  - platform: template
    name: "Desk M2 Height"
    id: "deskm2"
    filters:
    - lambda: !lambda |-
        if (x <1 ) return {};
        return x/10;
  - platform: template
    name: "Desk M3 Height"
    id: "deskm3"
    filters:
    - lambda: !lambda |-
        if (x <1 ) return {};
        return x/10;
  - platform: template
    name: "Desk M4 Height"
    id: "deskm4"
    filters:
    - lambda: !lambda |-
        if (x <1 ) return {};
        return x/10;                        

text_sensor:
  - platform: homeassistant
    id: movement_status
    entity_id: binary_sensor.presence
 

switch:
  - platform: template
    name: "Desk Enable"
    id: deskenable
    lambda: |-
      if (id(movement_status).state == "on") {
        return true;
      } else {
        return true;
      }
    turn_on_action:
      - logger.log: Desk Enabled
    on_turn_on:      
      - logger.log: Desk Enabled
    on_turn_off:
      - logger.log: Desk Disabled
      - delay: 100s
      - if:
         condition: 
            text_sensor.state:
              id: movement_status
              state: "off"
         then:
            - logger.log: Reset Desk to lowest setting.
            - uart.write: [0xf1, 0xf1, 0x05,0x00,0x05,0x7e]     



button:
  - platform: template
    name: Desk UP
    id: my_deskup
    on_press:
      if:
        condition:
      # Same syntax for is_off
          switch.is_on: deskenable      
        then:
        - logger.log: UP Pressed
        - uart.write: [0xf1, 0xf1, 0x01,0x00,0x01,0x7e]
  - platform: template
    name: Desk Down
    id: my_deskdown
    on_press:
      if:
        condition:
      # Same syntax for is_off
          switch.is_on: deskenable            
        then:
        - logger.log: DOWN Pressed
        - uart.write: [0xf1, 0xf1, 0x02,0x00,0x02,0x7e]      
  - platform: template
    name: Desk Sit
    id: my_desksit
    on_press:
      if:
        condition:
      # Same syntax for is_off
          switch.is_on: deskenable            
        then:
        - logger.log: SIT Pressed
        - uart.write: [0xf1, 0xf1, 0x05,0x00,0x05,0x7e]            
  - platform: template
    name: Desk Stand
    id: my_deskstamd
    on_press:
      if:
        condition:
      # Same syntax for is_off
          switch.is_on: deskenable            
        then:
        - logger.log: STAND Pressed
        - uart.write: [0xf1, 0xf1, 0x06,0x00,0x06,0x7e]  
  - platform: template
    name: Desk FULLUP
    id: my_deskfullup
    on_press:
      if:
        condition:
      # Same syntax for is_off
          switch.is_on: deskenable            
        then:
        - logger.log: FULLUP Pressed
        - uart.write: [0xf1, 0xf1, 0x28,0x00,0x28,0x7e]          
  - platform: template
    name: Desk test
    id: my_desktest
    on_press:
      then:
        - logger.log: TEST Pressed
        - uart.write: [0xf1, 0xf1, 0x07,0x00,0x07,0x7e,0xf1, 0xf1, 0x08,0x00,0x08,0x7e,0xf1, 0xf1, 0x09,0x00,0x09,0x7e,0xf1, 0xf1, 0x0c,0x00,0x0c,0x7e,0xf1, 0xf1, 0x0e,0x00,0x0e,0x7e]                   


number:               
  - platform: template
    name: "Desk Height Control"
    id: "deskSlider"
    step: 1
    min_value: 677
    max_value: 1241
    mode: slider            
    set_action:
      if:
        condition:
      # Same syntax for is_off
          switch.is_on: deskenable            
        then:
        - uart.write: !lambda |-
            int a= (int(x) & 0xff);
            int b= ((int(x) >> 8) & 0xff);
            int c= (a+b+0x80+0x02) & 0xff;
            return {0xf1, 0xf1, 0x80, 2, b,a,c,0x7e,0xf1, 0xf1, 0x1b, 0x00, 0x1b,0x7e};        
1 Like