This is for a Vari Desk, and works great, thank you for getting me going!
I’ve made a few changes and additions to the code, including making functional minimum and maximum values to stop movement, and added presets for sitting and standing (seemed easier than trying to simulate the physical buttons).
I also had to change the throttle on the height from 200ms to 4ms to overcome an issue whereby the height displayed in HA did not match what was displayed on the desk. It also appears to have made it a bit more accurate now as a full run from standing to sitting stopped EXACTLY where it should have, whereby it was previously off .1-.2".
I originally tried going from 200ms to 100ms and it was better, but still off once in a while. I chose 4ms because of this article: https://www.devmire.com/reverse-engineering-a-standing-desk-for-fun-and-profit/ Specifically, there was a comment in the code that stated “Height should be set in bursts of x ms pulses, as it takes 4ms to read the current height”.
I used an ESP32, Dupont jumpers (male/female), and one of these for pass-thru: Amazon.com: Teansic 2PCS RJ45 Ethernet Dual Female Terminal Breakout Board,3.5mm Pitch 8Pin RJ45 Screw Connector Board Shielded Network Adapter Terminal : Electronics All that’s needed for assembly is a tiny little screwdriver - no soldering!
I’ll be designing an enclosure for it in the near future.
Enjoy!
esphome:
name: small-desk
friendly_name: Small 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:
# Enable Home Assistant API
api:
ota:
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
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
desky:
id: desk_controller
timeout: 15s
height:
name: Desk Height
id: desk_height
accuracy_decimals: 1
unit_of_measurement: in
filters:
- delta: 0.05
- throttle: 4ms
- multiply: 0.1
on_value:
then:
#If the value changes, then the desk is moving
- binary_sensor.template.publish:
id: desk_is_moving
state: ON
- delay: 300ms
#Assume it's stopped moving if no height changes after a short time.
- binary_sensor.template.publish:
id: desk_is_moving
state: Off
binary_sensor:
- platform: template
id: desk_is_moving
name: "Desk Is Moving"
filters:
- delayed_off: 400ms
#If the desk isn't moving for a bit we better turn off attempts at movement. 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
#Go to height x
- platform: template
name: Go To Height x
id: go_to_preset_height_x
on_press:
then:
#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(desk_target_height).state < id(desk_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 (id(desk_height).state)<((id(desk_target_height).state) + (id(stopping_distance_in).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 (id(desk_height).state)>((id(desk_target_height).state) - (id(stopping_distance_in).state));
#Run until the difference between current and target state is <0.3cm
- switch.turn_off: raise_desk
#Go to sitting height
- platform: template
name: Go To Sitting Height
id: go_to_sitting_preset_height
on_press:
then:
#Check if we need to move desk up or down from current position
if:
condition:
#Current height is more than sitting height, then move desk down
lambda: |-
return id(desk_sitting_height).state < id(desk_height).state;
then:
- switch.turn_on: lower_desk
- wait_until:
#Run until the difference between current and sitting height is < stopping distance
condition:
lambda: return (id(desk_height).state)<((id(desk_sitting_height).state) + (id(stopping_distance_in).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 (id(desk_height).state)>((id(desk_sitting_height).state) - (id(stopping_distance_in).state));
#Run until the difference between current and sitting height < stopping distance
- switch.turn_off: raise_desk
#Go to standing height
- platform: template
name: Go To Standing Height
id: go_to_standing_preset_height
on_press:
then:
#Check if we need to move desk up or down from current position
if:
condition:
#Current height is more than standing height, then move desk down
lambda: |-
return id(desk_standing_height).state < id(desk_height).state;
then:
- switch.turn_on: lower_desk
- wait_until:
#Run until the difference between current and standing height is < stopping distance
condition:
lambda: return (id(desk_height).state)<((id(desk_standing_height).state) + (id(stopping_distance_in).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 (id(desk_height).state)>((id(desk_standing_height).state) - (id(stopping_distance_in).state));
#Run until the difference between current and standing height < stopping distance
- switch.turn_off: raise_desk
number:
- platform: template
id: desk_target_height
name: "Target Height x"
optimistic: true
unit_of_measurement: in
min_value: 29
max_value: 49
step: 0.1
- platform: template
id: lower_limit
name: "Lower Limit"
optimistic: True
unit_of_measurement: in
min_value: 27
max_value: 29
step: 0.1
restore_value: True
initial_value: 28
- platform: template
id: upper_limit
name: "Upper Limit"
optimistic: True
unit_of_measurement: in
min_value: 48
max_value: 50
step: 0.1
restore_value: True
initial_value: 49
- platform: template
name: "Stopping Distance Offset"
id: stopping_distance_in
unit_of_measurement: in
optimistic: true
min_value: .1
max_value: 1
step: 0.1
restore_value: true
initial_value: .4
- platform: template
id: desk_standing_height
name: "Standing Height"
optimistic: true
unit_of_measurement: in
#Limit the range
min_value: 45
max_value: 49
step: 0.1
restore_value: true
initial_value: 48
- platform: template
id: desk_sitting_height
name: "Sitting Height"
optimistic: true
unit_of_measurement: in
#Limit the range
min_value: 28.5
max_value: 32
step: 0.1
restore_value: true
initial_value: 30
switch:
#wake up the desk and request it sends its height
- platform: gpio
id: wake_desk_and_get_height
name: "Request Desk Height"
pin:
number: 14
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: 4
# mode: INPUT_PULLUP
inverted: true
interlock: lower_desk
on_turn_on:
- wait_until:
#Run until current > upper limit + stopping distance
condition:
lambda: return (id(desk_height).state)>((id(upper_limit).state) - (id(stopping_distance_in).state));
- switch.turn_off: raise_desk
#Lower the desk
- platform: gpio
id: lower_desk
name: "Lower Desk"
pin:
number: 5
# mode: INPUT_PULLUP
inverted: true
interlock: raise_desk
on_turn_on:
- wait_until:
#Run until current < lower limit + stopping distance
condition:
lambda: return (id(desk_height).state)<((id(lower_limit).state) + (id(stopping_distance_in).state));
#Auto off after 15s just in case
- switch.turn_off: lower_desk