Skip to content

Instantly share code, notes, and snippets.

@EverythingSmartHome
Created November 13, 2024 18:32
Show Gist options
  • Save EverythingSmartHome/e1faa5a9272fdcd066f346455e57ec9b to your computer and use it in GitHub Desktop.
Save EverythingSmartHome/e1faa5a9272fdcd066f346455e57ec9b to your computer and use it in GitHub Desktop.
flexispot-e7pro-voice-assistant
esphome:
friendly_name: flexispot-e7q
name: flexispot-e7q
platformio_options:
board_build.flash_mode: dio
on_boot:
- priority: -10
then:
- button.press: button_m
- priority: 600
then:
- output.turn_off: set_low_speaker
external_components:
source: github://iMicknl/LoctekMotion_IoT@v2
components: [ loctekmotion_desk_height ]
esp32:
board: esp32-s3-devkitc-1
flash_size: 8MB
framework:
type: esp-idf
# Enable logging
logger:
level: DEBUG
hardware_uart: UART0
# Enable Home Assistant API
api:
on_client_connected:
then:
- delay: 50ms
- micro_wake_word.start:
on_client_disconnected:
then:
- voice_assistant.stop:
ota:
- platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
output:
- platform: gpio
pin:
number: GPIO17
allow_other_uses: true
id: set_low_speaker
substitutions:
device_name: Flexispot EK5
name: flexispot_ek5
min_height: "63.6" # Min height + 0.1
max_height: "128.9" # Max height - 0.1
psram:
mode: octal
speed: 80MHz
uart:
id: desk_uart
baud_rate: 9600
tx_pin: 20
rx_pin: 19
i2s_audio:
i2s_lrclk_pin: GPIO16
i2s_bclk_pin: GPIO15
microphone:
- platform: i2s_audio
id: mic
adc_type: external
i2s_din_pin: GPIO18
channel: left
speaker:
- platform: i2s_audio
id: lil_speaker
dac_type: external
i2s_dout_pin:
number: GPIO17
allow_other_uses: true
micro_wake_word:
models:
- model: okay_nabu
on_wake_word_detected:
then:
- voice_assistant.start:
wake_word: !lambda return wake_word;
voice_assistant:
microphone: mic
speaker: lil_speaker
#use_wake_word: true
noise_suppression_level: 2
auto_gain: 31dBFS
volume_multiplier: 3.0
on_error:
- micro_wake_word.start:
on_end:
then:
- wait_until:
not:
voice_assistant.is_running:
- micro_wake_word.start:
sensor:
- platform: wifi_signal
name: "WiFi Signal"
update_interval: 60s
- platform: uptime
name: Uptime
- platform: loctekmotion_desk_height
id: "desk_height"
name: Desk Height
on_value_range:
- below: ${min_height}
then:
- switch.turn_off: switch_down
- above: ${max_height}
then:
- switch.turn_off: switch_up
on_value:
then:
- cover.template.publish:
id: desk_cover
position: !lambda |-
// The sensor outputs values from min_height (cm) to max_height (cm)
// We need to translate this to 0 - 1 scale.
float position = (float(x) - float(${min_height})) / (float(${max_height}) - float(${min_height}));
return position;
- component.update: set_desk_height
switch:
- platform: gpio
name: "Virtual Screen" # PIN20
pin:
number: 3
mode: OUTPUT
restore_mode: ALWAYS_ON
entity_category: "config"
internal: true
- platform: uart
name: "Up"
id: switch_up
icon: mdi:arrow-up-bold
data: [0x9b, 0x06, 0x02, 0x01, 0x00, 0xfc, 0xa0, 0x9d]
uart_id: desk_uart
send_every: 108ms
internal: true
- platform: uart
name: "Down"
id: switch_down
icon: mdi:arrow-down-bold
data: [0x9b, 0x06, 0x02, 0x02, 0x00, 0x0c, 0xa0, 0x9d]
uart_id: desk_uart
send_every: 108ms
internal: true
- platform: uart
name: "Alarm off"
id: switch_alarm
icon: mdi:alarm
data: [0x9b, 0x06, 0x02, 0x40, 0x00, 0xAC, 0x90, 0x9d]
uart_id: desk_uart
send_every: 108ms
on_turn_on:
- delay: 3000ms
- switch.turn_off: switch_alarm
entity_category: "config"
- platform: uart
name: "Child Lock"
id: switch_child_lock
icon: mdi:account-lock
data: [0x9b, 0x06, 0x02, 0x20, 0x00, 0xac, 0xb8, 0x9d]
uart_id: desk_uart
send_every: 108ms
on_turn_on:
- delay: 5000ms
- switch.turn_off: switch_child_lock
entity_category: "config"
button:
- platform: template
name: "Preset 1"
icon: mdi:numeric-1-box
on_press:
- uart.write:
id: desk_uart
data: [0x9b, 0x06, 0x02, 0x04, 0x00, 0xac, 0xa3, 0x9d]
- platform: template
name: "Preset 2"
icon: mdi:numeric-2-box
on_press:
- uart.write:
id: desk_uart
data: [0x9b, 0x06, 0x02, 0x08, 0x00, 0xac, 0xa6, 0x9d]
- platform: template
name: "Sit" # Preset 3 on some control panels
icon: mdi:chair-rolling
on_press:
- uart.write:
id: desk_uart
data: [0x9b, 0x06, 0x02, 0x00, 0x01, 0xac, 0x60, 0x9d]
- platform: template
name: "Stand" # Preset 4 on some control panels
icon: mdi:human-handsup
on_press:
- uart.write:
id: desk_uart
data: [0x9b, 0x06, 0x02, 0x10, 0x00, 0xac, 0xac, 0x9d]
- platform: template
name: "Memory"
id: button_m
icon: mdi:alpha-m-box
entity_category: "config"
on_press:
- uart.write:
id: desk_uart
data: [0x9b, 0x06, 0x02, 0x20, 0x00, 0xac, 0xb8, 0x9d]
- platform: template
name: "Wake Screen"
id: button_wake_screen
icon: mdi:gesture-tap-button
entity_category: "config"
on_press:
- uart.write:
id: desk_uart
data: [0x9b, 0x06, 0x02, 0x00, 0x00, 0x6c, 0xa1, 0x9d]
- platform: template
name: "Alarm"
id: button_alarm
icon: mdi:alarm
on_press:
- uart.write:
id: desk_uart
data: [0x9b, 0x06, 0x02, 0x40, 0x00, 0xAC, 0x90, 0x9d]
- platform: restart
name: "Restart"
entity_category: "config"
cover:
- platform: template
id: "desk_cover"
icon: mdi:desk # or mdi:human-male-height-variant
name: "Desk"
device_class: blind # makes it easier to integrate with Google/Alexa
has_position: true
position_action:
- if:
condition:
- lambda: !lambda |-
return pos > id(desk_cover).position;
then:
- cover.open: desk_cover
- wait_until:
lambda: |-
return id(desk_cover).position >= pos;
- cover.stop: desk_cover
else:
- cover.close: desk_cover
- wait_until:
lambda: |-
return id(desk_cover).position <= pos;
- cover.stop: desk_cover
stop_action:
- switch.turn_off: switch_up
- switch.turn_off: switch_down
open_action:
- switch.turn_off: switch_down
- switch.turn_on: switch_up
close_action:
- switch.turn_off: switch_up
- switch.turn_on: switch_down
optimistic: false
number:
- platform: template
name: "Desk Height"
id: set_desk_height
min_value: ${min_height}
max_value: ${max_height}
icon: "mdi:counter"
unit_of_measurement: "cm"
device_class: "distance"
step: 0.1
lambda: !lambda |-
return id(desk_height).state;
set_action:
- if:
condition:
- lambda: !lambda |-
return x > id(desk_height).state;
then:
- cover.open: desk_cover
- wait_until:
lambda: |-
return id(desk_height).state >= x;
- cover.stop: desk_cover
else:
- cover.close: desk_cover
- wait_until:
lambda: |-
return id(desk_height).state <= x;
- cover.stop: desk_cover
@EverythingSmartHome
Copy link
Author

Wiring Diagram (Please check your controller model as it may differ from desk to desk):

Flexispot wiring diagram

@sibero80
Copy link

Thank you for sharing this!
I found my standing desk´s documentation on interfacing with their controller.
image
Could you shed some light into how could I adapt your code to their hex commands? I gave it a shot, but not sure if I translated it correctly.

  - platform: uart
    name: "Down"
    id: switch_down
    icon: mdi:arrow-down-bold
    data: [0x01, 0x06, 0x00, 0x01, 0x00, 0x04, 0xd9, 0xc9]
    uart_id: desk_uart
    send_every: 108ms
    internal: true

@jamesmyatt
Copy link

jamesmyatt commented Nov 15, 2024

@sibero80 Do you have a link for that table?

If it's loctekmotion, then I think you need the 0x9b and 0x9d start and end bytes.

@sibero80
Copy link

@sibero80 Do you have a link for that table?

It's loctekmotion, then I think you need the 0x9b and 0x9d start and end bytes.

It Dihool brand is a 4-ch controller I bought to Frankenstein my very large L-shaped desk, which needs 4 linear actuators.

Here's the full manual.

Do you think my translated code would work as-is? I can try it on my own. Is there any risk for controllers if I send a malformed packet?

@jamesmyatt
Copy link

Almost certainly won't work if it's not a loctekmotion controller.

But it looks like you just need an RS485 to Serial converter, as on page 11. And you don't need the esphome component, which does the interpretation of the 7-segment display codes to height reading.

@lostless13
Copy link

Did you use the same wiring and yaml file for your E7 Pro? Mine is running controller CB38M2L-(IB)-4 and interface HS13A-1C0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment