I faced some questions using your solution @ssieb. What is meant by desk_uart
and remote_uart
? I don’t know what this is supposed to do. For now I created an uart-object in yaml. But for this solution I need 2 I guess?
It should be as you guess I’m relatively sure. You need to define two uarts.
One is from the perspective of what is being sent/received by the control box, the other from the perspective of the control panel.
But why do we need 2 uarts? Thats what I don’t really get.
I probably can’t explain so well.
But I think it’s because that it’s “two way communication”, you need to be able to both read AND write to each of the tx and rx.
My guess/ understanding…
.
I also understand, that these are the segment-values. But this works only for the first decimal-position and the tens-digits, like you can see in this screenshot:
Interesting is, that at the Units, the last 4 bits are the same, but the first 4 ones are different. (0xBF
→ 0x3F
; 0x86
→ 0x06
; …)
Nevermind. I got the example working in my own repo. I made a new branch for using your code-snippts: GitHub - MhouneyLH/esphome_custom_components at feat/using_ssieb_code
I had to fix some things. This weekend I will try to get the desk moving with this new (and better + lightweight) version from you @ssieb. Thanks for this amazing hint on your repo! Until now I had always overlooked the different branches of your repo.
Great News - The desk is movable by software!
Summary of what I did the last few days
I already updated my repository on GitHub: GitHub - MhouneyLH/esphome_custom_components: A collection of custom components for esphome.
The desk can move up and down. Finally. I used the G-Pin
(the second one) for showing the controller-box that something has to move. I augmented my adapter-construction with another white-cable for the touchpad-tx (in the code this is remote-uart
). With that one I can write the corresponding messages via uart.
But how does the desk know, if it should go up or down?
I have defined a function called move_to(target_height)
. It checks the boundaries, sets the new target-height and updates the current-operation based on the current-height:
void Desktronic::move_to(const float height_in_cm)
{
if (height_in_cm < MIN_HEIGHT || height_in_cm > MAX_HEIGHT)
{
ESP_LOGE(TAG, "Moving: Height must be between 72.0 and 119.0 cm");
return;
}
target_height_ = height_in_cm;
current_operation = must_move_up(height_in_cm) ? DESKTRONIC_OPERATION_RAISING : DESKTRONIC_OPERATION_LOWERING;
}
The main-loop looks like this (no need to move, if we are idling anyway):
void Desktronic::loop()
{
read_desk_uart();
if (current_operation == DesktronicOperation::DESKTRONIC_OPERATION_IDLE)
{
read_remote_uart();
return;
}
move_to_target_height();
}
The read_desk_uart()
-method updates the current_height_
. That’s pretty important for the later check, if the target-height is reached or if the desk should move further more. This check you will see in the move_to_target_height()
-method.
The interesting part is the move_to_target_height()
-method. Summarized, I do some checks at the beginning, check wether I have to move up or down and do that until I reach the wished height (inside of the target-boundaries). The target boundaries are defined with a deviation from the target height of 0.6cm. The move_pin_
is the G-Pin
in this case, which has to be high when moving:
void Desktronic::move_to_target_height()
{
if (!move_pin_)
{
ESP_LOGE(TAG, "Moving: Move pin is not configured");
return;
}
if (!remote_uart_)
{
ESP_LOGE(TAG, "Moving: Remote UART is not configured");
return;
}
if (!isCurrentHeightValid())
{
ESP_LOGE(TAG, "Moving: Height must be between 72.0 and 119.0 cm");
move_pin_->digital_write(false);
current_operation = DesktronicOperation::DESKTRONIC_OPERATION_IDLE;
return;
}
move_pin_->digital_write(true);
switch (current_operation)
{
case DesktronicOperation::DESKTRONIC_OPERATION_RAISING:
ESP_LOGE(TAG, "Moving: Up");
for (int i = 0; i < REMOTE_UART_SEND_MESSAGE_COUNT; i++)
{
remote_uart_->write_array(REMOTE_UART_MESSAGE_MOVE_UP, REMOTE_UART_MESSAGE_LENGTH);
}
break;
case DesktronicOperation::DESKTRONIC_OPERATION_LOWERING:
ESP_LOGE(TAG, "Moving: Down");
for (int i = 0; i < REMOTE_UART_SEND_MESSAGE_COUNT; i++)
{
remote_uart_->write_array(REMOTE_UART_MESSAGE_MOVE_DOWN, REMOTE_UART_MESSAGE_LENGTH);
}
break;
default:
return;
}
if (isCurrentHeightInTargetBoundaries())
{
ESP_LOGE(TAG, "Moving: Finished");
move_pin_->digital_write(false);
current_operation = DesktronicOperation::DESKTRONIC_OPERATION_IDLE;
}
}
I was also able to reduce the flash memory to 44%. I removed unneeded header files as well as yaml configurations that are useless now. My yaml file now looks like this:
esphome:
name: esphome-web-755eb2
esp8266:
board: esp01_1m
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: ...
ota:
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
manual_ip:
static_ip: ...
gateway: ...
subnet: ...
external_components:
- source:
type: git
url: https://github.com/MhouneyLH/esphome_custom_components
ref: develop
refresh: 4s
components: [ desktronic ]
uart:
- id: desk_bus
tx_pin: 5 # D1
rx_pin: 4 # D2
baud_rate: 9600
- id: remote_bus
tx_pin: 3 # RX
rx_pin: 1 # TX
baud_rate: 9600
desktronic:
id: my_desktronic
desk_uart: desk_bus
remote_uart: remote_bus
height:
name: Desk Height
move_pin:
number: 14 # D5
up:
name: Up Button
down:
name: Down Button
memory1:
name: Memory1 Button
memory2:
name: Memory2 Button
memory3:
name: Memory3 Button
switch:
- id: move_switch
name: ↑↓
platform: gpio
pin:
number: 2 # D4
inverted: true
on_turn_on:
then:
- lambda: id(my_desktronic).move_to(80.0);
# - lambda: id(my_desktronic).stop();
binary_sensor:
- id: is_moving_bsensor
name: Desk is moving
platform: template
lambda: return id(my_desktronic).current_operation != desktronic::DESKTRONIC_OPERATION_IDLE;
For more information about the code, etc. you can check the mentioned repository. With this state of the project, I accomplished a major (and the most difficult intermediate step) of the planned project. Thank you, especially @Mahko_Mahko and @ssieb!
The next steps and goals
- currently it is not possible to see the current height or other stuff on the touchpad, when the remote-tx is connected to the chip.
→ potential solution: use a third uart-bus for sending the remote-tx-data separately. - I want to create a more beautiful ui in HomeAssistant.
- I want to connect a weight-sensor to the home-assistant eco-system. The weight-sensor lays under my chair and if I sit down, the desk automatically goes down.
- add 2 methods with which I can adjust the height of the desk one by one. (so I dont have to give it a fixed height everytime)
- improving the hardware circumstances: At the moment, I have soldered the chip on improperly. I should now do this again properly because I noticed in between that there were some loose contacts.
Nice one!
For chair occupancy take a look at items 1 and 13 here. You might find a battery operated device works better for a chair.
Do you have a wiring diagram you could share please?
I’m actually working on a similar project that uses a pass through set-up and I’m not sure how to wire for reading and writing to both the rx and tx. I understand you had to do something like this for your set-up. Sorry if I’ve missed it.
https://community.home-assistant.io/t/i-scored-a-scorbot-er-iii/540324/2?u=mahko_mahko
I could create a diagram. But this weekend I’m busy with other stuff. I could create one next week.
Hey, I wanted to give a short update.
@Mahko_Mahko I did not have forgotten the diagram, but I did not had the time since a few weeks.
Thats a not completely finished diagram, if you still need it:
Currently I am working on a project to control the desk via app on a smartphone. The progress you can see in this repository. A friend of mine also made a nicer connection to the chip with properly soldered cables.
Nice. Thanks for getting back to me. I figured it out with some help from some people on Discord though.
My “Man in the middle” wiring looks like this.
The green wire both intercepts and injects uart messages. For the yellow wire I only need to read the messages.
I need the max3232 convertors to convert the 12v logic to 5v and back again.
Thank you for the great project base!
I have a similar odd desk.
I am embarrassed to be still very confused about the wiring to the ESP dongle between desk and the controller, and how the UART wires should be.
The cable itself has 10 pins, which i counted after ordering the expanders from Aliexpress with 8 pins But i discarded the outermost ones that control the 12 Volts, and it almost works, it fits to the base nicely and i can use the inner 8.
But here are the problems:
- When inserting WHITE to TX on ESP32, i can get the binary sensors (pressed button up, button down, etc)
- When inserting WHITE to RX on ESP32, i can get the table to move with buttons
- Modified your cpp code to expose more public functions for testing, so i can move it up or down.
void move_to_from(const float height_in_cm, const float current_height);
void move_to(const float height_in_cm);
void stop();
void move_up();
void move_down();
void move_to_memory_1();
void move_to_memory_2();
- But never have I got the desk height
- Not have I got the dongle to work together with the physical controller. The display just says 888. and buttons dont work.
So about wiring:
- should I keep the existing connection between table and controller, and add my wires for ESP just in the middle?
- or remove the existing WHITE and BLACK to just go through my ESP32?
- i have 2 uart buses configured, where do the wires go? exactly?
- id: remote_bus
tx_pin: 1 # when WHITE - allows to control the desk
rx_pin: 3 # when WHITE - reads sensor data from controller
# together they break
- id: desk_bus
rx_pin: 17 # no combo does anything
tx_pin: 16 # no combo does anything
I’m ashamed to have spent too much time on this, and now I just want to finish it out of spite.
Tried the uart_mitm component for no avail.
So I almost hacked out the height from desk, logging and reading the hex data, parsing it to numbers (without proper wiring):
debug:
direction: BOTH
dummy_receiver: true
after:
delimiter: "\xA5"
sequence:
- lambda: |-
UARTDebug::log_hex(direction , bytes, ','); //Still log the data
auto uart_direction = "IDK";
if (direction = uart::UART_DIRECTION_TX ){
uart_direction = "TX: ";
}
else if (direction = uart::UART_DIRECTION_RX ){
uart_direction = "RX_ ";
}
auto bytes_size = bytes.size();
std::string log_message = uart_direction;
for(int i = 0; i < bytes_size; ++i){
char buffer[4];
sprintf(buffer, "%02x ", bytes[i + bytes_size - 1 ]);
log_message += buffer;
}
if ( bytes_size >= 5){
ESP_LOGW("desk_bus", "%s", log_message.c_str());
}
else {
ESP_LOGI("desk_bus", "%s", log_message.c_str());
}
even got this far as to read the height value out of the uart buffer, somewhat semi-consistently:
script:
- id: get_debug_height
mode: single
then:
- lambda: |-
// provided map gives error on "4" // data[2] is data2 = EDGE CASE if contain 4 (74, 84, 94, 104, 114, 124)
// static const int SEGMENT_MAP[10] = {0x3f, 0x06, 0x5b, 0x4f, 0x67, 0x6d, 0x7d, 0x07, 0x7f, 0x6f};
// 0 1 2 3 4 5 6 7 8 9
static const int SEGMENT_MAP[10] = {0x3f, 0x06, 0x5b, 0x4f, 0x67, 0x6d, 0x7d, 0x07, 0x7f, 0x6f};
//0x66
uint8_t data[5];
while (id(desk_uart).available() >= 5) {
id(desk_uart).read_array(data, 5);
if (data[0] != 0x5A) {
ESP_LOGE("seisuk", "[0] %02x must be 0x5A, [3] is %02x", data[1], data[3]);
//break;
continue;
}
if ((data[1] | data[2] | data[3]) == 0x00) {
ESP_LOGD("seisuk", "null height");
//break;
continue;
}
int data0 = -1, data1 = -1, data2 = -1;
for (int i = 0; i < 10; i++) {
if (data[1] == SEGMENT_MAP[i]) data0 = i;
if (data[2] == SEGMENT_MAP[i]) data1 = i;
if (data[3] == SEGMENT_MAP[i]) data2 = i;
}
float got_height = 0.0;
if (data0 < 0 || data1 < 0 || data2 < 0) {
if (data0 < 0 ) {
ESP_LOGE("data", "data0: %02x", data[1] ); // if ( data[1] != 0x00 ) { }
}
if (data1 < 0 ) {
// true for values above 100, false for below 100
ESP_LOGW("data", "data1: %02x", data[2] ); // if ( data[2] != 0x00 ) { }
}
if (data2 < 0 ) {
ESP_LOGW("seisuk", "data2: %02x", data[3] );
}
//break;
continue;
}
// get decimal
int decimal = ((~data[4] + 256) % 256) / 10;
// sum if up
got_height = data0 * 100 + data1 * 10 + data2 + decimal * 0.1;
add decimal
//if (got_height >= 100.0){
// got_height += decimal * 0.1;
//}
// If belo 3 digis, e.g 100
// INVERT HEIGHT FOR BELOW ZERO
if (data[2] & 0x80 && data1 < 0) {
got_height = got_height / 10 + 10;
float under_99 = ( ( ~data[4] + 256 ) % 256 );
if (under_99 > 100 ){
//under_99 /= 10;
}
float inverted = ( ( data[4] + 256 ) % 256); // + 100;
if (inverted > 100 ){
//inverted /= 10;
}
float reinverted = ( ( data[4] ) % 256) / 2; // + 100;
if (reinverted < 10 ){
//reinverted *= 10;
}
if (under_99 < 101 && under_99 > 65 ){ // && under_99 != 68.00
ESP_LOGI("under_99", "%.2f", under_99 );
}
if (inverted < 101 && inverted > 65 ){
ESP_LOGW("inverted", "%.2f", inverted );
}
if (reinverted < 101 && reinverted > 65 ){ // && reinverted != 100.00
ESP_LOGE("reinverted", "%.2f", reinverted );
}
if (data1 < 0 ) {
// ESP_LOGE("data1", "%02x", data[2] ); // if ( data[2] != 0x00 ) { }
}
if (under_99 <= 100 && under_99 > 66 ){
//got_height = under_99;
//ESP_LOGI("got_height", "%.2f", under_99);
}
if (got_height <= 100 ){
ESP_LOGI("lt100", " %.1f", got_height );
}
}
// IF BELOW 100, divide by 10, get decimal place
ESP_LOGW("height", "data[2]: %02x, data1: %d", data[2], data1);
// IF ALL IS CORRECT, PUBLISH VALUES, DO STUFF
if (got_height <= id(max_height) && got_height >= id(min_height) ){
ESP_LOGI("height", "%.1f ", got_height );
id(uart_height).publish_state(got_height);
id(height) = got_height;
}
if (got_height >= id(max_height) || got_height <= id(min_height) ){
id(seisuk).stop();
}
}
I haven’t been following this in detail, but based on my experiences with another project, here is how I believe uart wiring needs to be for two controlling devices to be able to issue commands…
-
If you only need to “read signals on a wire” (listen to them, let them “pass through”, but not inject your own commands), then you can just “Hop” the wire. See yellow wire.
-
If you need to both read signals on the wire and inject your own (listen for keypad presses and insert your own from the ESP), then the wire must only pass through the ESP via a “uart forward”. This is where I got stuck for a long time with my project. I believe this is key to a “Man-In-The-Middle” (MITM) set-up. See green wire. If you try to hop a signal you need to both read and write from, it won’t work when both devices are connected.
In my diagram, you can pretend the convertors aren’t there (wires go straight through). Pendant is control panel. Robot is desk control box.
I’m not 100% if this applies to this project, but it took me a while to figure this out so sharing in case it is of use.
I also found for my project that the MITM may introduce a small lag as it recieves and forwards uart messages. This may or may not create issues if communication is two way (there is a request that waits for a response and may timeout).
As wire colors are different, I only have black and white to play with, and red for control takeover. I use green/purple to power the ESP. Yellow and Brown are ignored because I messed up buying the 8-pin over 10-pin cable expander This means I cant get USB power from the control panel, but that’s okay for now…
I can do without knowing the binary sensors for if controller button is pressed, i just would like to get the desk height, so i can move it to set height. Currently using my modified code i can move it up and down with switches, but since i dont know the height, i cant set the position…
P → Key1 # RED = P (Panel?)
R → D-TX # BLACK = Rx
T → D-RX # WHITE = TX
5 → +5V # GREEN = 5g
G → G # PURPLE = GND
YELLOW = DC + 12v
BROWN = DC_G - 12v
Are the height messages the same protocol as the OP? I assume they are on the black wire?
Good find, they are not exactly the same. As when using the original external component, I didn’t get anything as height, but with my custom lambda script at least something did come out…
// provided map gives error on "4" // data[2] is data2 = EDGE CASE if contain 4 (74, 84, 94, 104, 114, 124)
// static const int SEGMENT_MAP[10] = {0x3f, 0x06, 0x5b, 0x4f, 0x67, 0x6d, 0x7d, 0x07, 0x7f, 0x6f};
// 0 1 2 3 4 5 6 7 8 9
static const int SEGMENT_MAP[10] = {0x3f, 0x06, 0x5b, 0x4f, 0x67, 0x6d, 0x7d, 0x07, 0x7f, 0x6f};
using the original map i logged some weird jumps, and missing numbers (the component provided sensor didn’t work still):
5A,07,FF,7F,85 -> 138.0
5A,07,FF,7F,85 -> 138.0
5A,07,FF,6F,75 -> 136.0
5A,07,FF,6F,75 -> 136.0
5A,07,EF,3F,35 -> 113.0
5A,07,EF,3F,35 -> 113.0
5A,07,EF,06,FC -> 110.0
5A,07,EF,06,FC -> 110.0
5A,07,EF,5B,51 -> 112.0
5A,07,EF,4F,45 -> 113.0
5A,07,EF,4F,45 -> 113.0
5A,07,EF,6D,63 -> 114.0
5A,07,EF,6D,63 -> 114.0
5A,07,EF,07,FD -> 110.0
5A,07,EF,07,FD -> 110.0
5A,07,EF,6F,65 -> 115.0
5A,07,EF,6F,65 -> 115.0
5A,7D,FD,4F,C9 -> 64,9
5A,7D,FD,5B,D5 -> 62,5
5A,7D,FD,3F,B9 -> 60,9
5A,7D,ED,6F,D9 -> 79,9
5A,7D,ED,07,71 -> 77,1
5A,7D,ED,6D,D7 -> 75,7
5A,7D,ED,66,D0 -> 74,0
5A,7D,ED,4F,B9 -> 73,9
5A,7D,ED,5B,C5 -> 72,5
5A,7D,ED,06,70 -> 71,0
5A,7D,ED,3F,A9 -> 70,9
5A,7D,FD,6D,E7 -> 65,4
5A,7D,FD,07,81 -> 67,1
5A,7D,FD,7F,F9 -> 68,9
5A,7D,FD,6F,E9 -> 69,9
5A,7D,FD,4F,C9
5A,7D,FD,5B,D5 -> 62,5
5A,7D,FD,3F,B9 -> 60,9
5A,7D,ED,6F,D9 -> 79,9
5A,7D,ED,07,71 -> 77,1
5A,7D,ED,6D,D7 -> 75,7
5A,7D,ED,66,D0 -> 74,0
5A,7D,ED,4F,B9 -> 73,9
5A,7D,ED,5B,C5 -> 72,5
5A,7D,ED,06,70 -> 71,0
5A,7D,ED,3F,A9 -> 70,9
5A,7D,FD,6D,E7 -> 65,4
5A,7D,FD,07,81 -> 67,1
5A,7D,FD,7F,F9 -> 68,9
5A,7D,FD,6F,E9 -> 69,9 - bottom target reached
Got it working through some ugly hacks Forgot to post, hope this will help someone else. Buttons on keypad and the screen is not working though, maybe i’ll deal with it in the future. Maybe even add some fun things, since its possible to write random stuff on the 7-segment-display · GitHub Topics · GitHub
substitutions:
friendly_name: 'Seisuk'
device_name: 'seisuk'
node_name: 'seisuk'
device_description: 'Seisuk AOKE WP-H01 WP-CB01-001 Desktronic/JSDRIVE DCU_G-PRT5G'
project_base: 'AOKE' # https://aoke-europe.com/troubleshooting
project_name: 'WP-H01' # panel
project_version: 'WP-CB01-001' # control box # https://aoke-europe.com/mwdownloads/download/link/id/88/
# https://profeqprofessional.nl/media/productattach//e/r/error_codes_wp-cb01-001_2.pdf
# https://motionwise-products.com/wp-content/uploads/2018/11/MotionWise_sf_Manual_081318_E_Rev-USB.pdf
# https://profeqprofessional.nl/media/productattach//e/r/error_codes_wp-cb01-001_2.pdf
min_height: "65.5" # real 65 # Min height + 0.5
max_height: "129.5" # real 130 # Max height - 0.5
initial_value: "90"
globals:
- id: height
type: float
restore_value: yes
initial_value: '100.0'
- id: min_height
type: float
restore_value: yes
initial_value: '65.5'
- id: max_height
type: float
restore_value: yes
initial_value: '129.5'
esphome:
name: ${device_name}
friendly_name: ${friendly_name}
name_add_mac_suffix: false
comment: ${device_description}
project:
name: ${project_base}.${project_name}
version: $project_version
on_boot:
- priority: 600.0
then:
- button.press: stop
- priority: -200.0
then:
- lambda: |-
id(uart_height).publish_state( id(height) );
esp8266:
board: nodemcu
early_pin_init: false
restore_from_flash: true
packages:
device_base: !include common/device.base.yaml
ota:
on_begin:
then:
- button.press: stop
logger:
esp8266_store_log_strings_in_flash: false
level: DEBUG
baud_rate: 0
uart:
- id: remote_bus
tx_pin: 1 # WHITE (2nd pin)
rx_pin: 3 # N/A (3rd pin)
baud_rate: 9600
- id: desk_bus
tx_pin: 4 # N/A (D2)
rx_pin: 5 # BLACK (D1)
baud_rate: 9600
rx_buffer_size: 256
external_components:
- source: components
components: [ desktronic ]
desktronic:
id: seisuk
desk_uart: desk_bus
remote_uart: remote_bus
height:
name: Wnotworkign desktronic Height
id: desk_height_sensor
icon: mdi:human-male-height
device_class: distance
unit_of_measurement: cm
accuracy_decimals: 1
internal: true
move_pin:
number: 14 # (D5)
binary_sensor:
- id: moving
name: Moving
platform: template
device_class: moving
icon: mdi:hand-back-right-off
lambda: return id(seisuk).current_operation != desktronic::DESKTRONIC_OPERATION_IDLE;
on_state:
- while:
condition:
binary_sensor.is_on: moving
then:
- script.execute: get_debug_height
- delay: 50ms
- id: going_up
name: Moving up
platform: template
device_class: moving
icon: mdi:transfer-up
entity_category: diagnostic
lambda: return (id(seisuk).current_operation == desktronic::DESKTRONIC_OPERATION_RAISING) || (id(seisuk).current_operation == desktronic::DESKTRONIC_OPERATION_UP);
- id: going_down
name: Moving down
platform: template
device_class: moving
icon: mdi:transfer-down
entity_category: diagnostic
lambda: return (id(seisuk).current_operation == desktronic::DESKTRONIC_OPERATION_LOWERING) || (id(seisuk).current_operation == desktronic::DESKTRONIC_OPERATION_DOWN);
sensor:
- id: uart_height
platform: template
name: Height
icon: mdi:human-male-height
device_class: distance
unit_of_measurement: cm
accuracy_decimals: 1
update_interval: never
lambda: |-
float current = id(height);
return current;
number:
- platform: template
id: desk_height
name: Height
icon: mdi:human-male-height-variant
min_value: $min_height
max_value: $max_height
lambda: |-
return id(height);
device_class: distance
unit_of_measurement: cm
update_interval: never
mode: box
step: 0.1
set_action:
then:
- while:
condition:
- lambda: |-
float to = std::round(x * 10) / 10;
float from = std::round(id(height) * 10) / 10;
if ( to != from ) {
return true;
}
else{
return false;
}
then:
- script.execute:
id: move_it
to: !lambda 'return x;'
- delay: 150ms
cover:
- platform: template
name: None
optimistic: true
device_class: damper
icon: mdi:desk
assumed_state: true
has_position: true
lambda: |-
auto value = (int)id(height);
float percentage = (float)(value - id(min_height)) / (id(max_height) - id(min_height));
return percentage;
open_action:
- number.set:
id: desk_height
value: $max_height
close_action:
- number.set:
id: desk_height
value: $min_height
stop_action:
- button.press: stop
position_action:
- number.set:
id: desk_height
value: !lambda |-
int value = id(min_height) + (int)( ( pos ) * (id(max_height) - id(min_height)) );
return value;
button:
- platform: template
name: Stop
icon: mdi:stop
entity_category: config
id: stop
on_press:
then:
- switch.turn_off: takeover
- script.stop: move_it
- switch.turn_off: switch_up
- switch.turn_off: switch_down
- lambda: |-
id(seisuk).stop();
- number.set:
id: desk_height
value: !lambda |-
float x = id(height);
return x;
- component.update: desk_height
switch:
- platform: gpio
name: Takeover
icon: mdi:gesture-tap
id: takeover
pin:
number: 14 # (D5)
mode: OUTPUT
restore_mode: ALWAYS_OFF
entity_category: diagnostic
disabled_by_default: true
on_turn_on:
then:
- delay: 50ms
- switch.turn_off: takeover
- platform: template
optimistic: true
name: Move Up
entity_category: config
restore_mode: ALWAYS_OFF
icon: mdi:arrow-up-bold-box
id: switch_up
on_turn_on:
then:
- switch.turn_on: takeover
- switch.turn_off: switch_down
- lambda: |-
id(seisuk).move_up();
on_turn_off:
then:
button.press: stop
- platform: template
name: Move Down
entity_category: config
restore_mode: ALWAYS_OFF
optimistic: true
icon: mdi:arrow-down-bold-box
id: switch_down
on_turn_on:
then:
- switch.turn_on: takeover
- switch.turn_off: switch_up # interlock: [up]
- lambda: |-
id(seisuk).move_down();
on_turn_off:
then:
button.press: stop
script:
- id: move_it
parameters:
to: float
mode: restart
then:
- if:
condition:
- binary_sensor.is_off: moving
then:
- lambda: |-
float target = std::round(to * 10) / 10;
float from = std::round(id(height) * 10) / 10;
ESP_LOGI("seisuk", "target %.1f from %.1f", target, from);
if ( target != from ) {
if ( target < from ) {
id(switch_down).turn_on();
}
else if ( target > from ) {
id(switch_up).turn_on();
}
else if ( target == from ) {
id(stop).press();
ESP_LOGI("seisuk", "target == from");
}
else {
id(stop).press();
ESP_LOGI("seisuk", "else height same");
}
}
else{
id(stop).press();
ESP_LOGI("seisuk", "height not not same");
}
else:
- if:
condition:
- binary_sensor.is_on: going_up
then:
- lambda: |-
float target = std::round(to * 10) / 10;
float from = std::round(id(uart_height).state * 10) / 10;
ESP_LOGI("seisuk", "moving to %.1f from %.1f", target, from);
if ( target <= from ) {
id(stop).press();
ESP_LOGE("seisuk", "height more");
auto call = id(desk_height).make_call();
call.set_value(id(uart_height).state);
call.perform();
}
- if:
condition:
- binary_sensor.is_on: going_down
then:
- lambda: |-
float target = std::round(to * 10) / 10;
float from = std::round(id(uart_height).state * 10) / 10;
ESP_LOGI("seisuk", "moving to %.1f from %.1f", target, from);
if ( target >= from ) {
id(stop).press();
ESP_LOGE("seisuk", "height less");
auto call = id(desk_height).make_call();
call.set_value(id(uart_height).state);
call.perform();
}
- delay: 100ms
- id: get_debug_height
mode: single
then:
- lambda: |-
// before continuing tell its not really moving
// id(moving).publish_state(false);
// id(going_up).publish_state(false);
// id(going_down).publish_state(false);
uint8_t data[5];
while (id(desk_bus).available() >= 5) {
id(desk_bus).read_array(data, 5);
if (data[0] != 0x5A) {
break;
}
if ((data[1] | data[2] | data[3]) == 0x00) {
break;
}
enum Segment : uint8_t
{
SEGMENT_INVALID = 0x00,
SEGMENT_0 = 0x3f,
SEGMENT_1 = 0x06,
SEGMENT_2 = 0x5b,
SEGMENT_3 = 0x4f,
SEGMENT_4 = 0x67,
SEGMENT_5 = 0x6d,
SEGMENT_6 = 0x7d,
SEGMENT_7 = 0x07,
SEGMENT_8 = 0x7f,
SEGMENT_9 = 0x6f,
};
auto segment_to_number = [](const uint8_t segment) {
switch (segment & 0x7f)
{
case SEGMENT_0:
return 0;
case SEGMENT_1:
return 1;
case SEGMENT_2:
return 2;
case SEGMENT_3:
return 3;
case SEGMENT_4:
return 4;
case SEGMENT_5:
return 5;
case SEGMENT_6:
return 6;
case SEGMENT_7:
return 7;
case SEGMENT_8:
return 8;
case SEGMENT_9:
return 9;
default:
ESP_LOGD("desktronic", "idk");
}
return -1;
};
int data0 = segment_to_number(data[1]);
int data1 = segment_to_number(data[2]);
int data2 = segment_to_number(data[3]);
float got_height = 0.0;
if (data0 < 0x00 || data1 < 0x00 || data2 < 0x00) {
break;
}
got_height = data0 * 100 + data1 * 10 + data2; // + decimal * 0.1;
// flip height for below 100
if (data[2] & 0x80 ) {
got_height /= 10.0;
}
// If all correct, publish values
if (got_height <= id(max_height) - 0.5 && got_height >= id(min_height) + 0.5 ){
id(height) = got_height;
id(uart_height).publish_state(got_height);
}
if (got_height >= id(max_height) || got_height <= id(min_height) ){
// id(stop).press();
ESP_LOGE("seisuk","stopped, out of bounds");
}
// now its moving
// id(moving).publish_state(true);
// id(going_up).publish_state(true);
// id(going_down).publish_state(true);
}
- delay: 50ms
Converting it to template cover is really nice, and allows exposing to to Google Home for voice control
Thanks again for the code @MhouneyLH!
Hey @veli, the interface for controlling the desk in HomeAssistant looks pretty good! I will have a look at it, as this was my first project using HomeAssistant
I haven’t been working on the desk project for the last few months, so I haven’t checked the forum at all. Sorry about that. But I’m glad to see it’s working for you now. It took me a few weeks to figure out how to modify the desk. You should not feel bad about the time you invested. The result (and of course the adventure) is what counts
I am currently working on an app that will allow you to control the desk with your smartphone. For the app I will have to update the component a bit. I will try to keep this thread updated. I don’t know if anyone would use it, but theoretically you could test the app on your desk.
An app separate from HA/ESPHome? Happy to test it, but personally I use HA to get rid of extra apps
I had a small business plan (too lazy to execute it, feel free to steal or collaborate with me) of creating the dongles to sell to our local standing desk manufacturer. An app would for sure be a necessity for that since their customers woult not use HA or like to connect to the ESP AP to control it…
I rewrote bits of the component, hence using it as this - public functions, more binary sensors, etc:
- source: components
components: [ desktronic ]