Thanks! No I actually have the bigger controller with 4 memories. Will give it a try now
Iāve got mine on casters so clearly Iām not the right target audience but I still find this totally awesome.
Maybe whenever I get around to putting my 77" TV on a standing desk frame I do the same.
There is some very cool rj12 port protocol decoding happening here.
Not sure if it applies to all models.
Iām posting my progress here
@Mahko_Mahko the cmd you tested not all were the new ones I found, some I believe were already known. But great to see you are already testing and something works!
I would like for you guys to test out the new cmd I found ands I can start a compatibility table based on your feedback.
I believe you guys lacked the stop command and the GoToHeight(mm) cmd, this later one works in my desks perfectly with soft stop accurate to the millimeter. I also think I found out how to change the memory presets to a desired hight, independently of were the desk is.
From my findings there are 2 adapters and 2 apps, I could not find an APK for the original app, just for the current one, so not all desks will be compatible with all of the commands I suspect, or maybe not and all of them work, better even, you guys share your findings
There are parts of the code I donāt understand yet, and there are things that I havenāt documented yet, Iām also planning on writing some custom code because I own 2 desks that are side by side, so I want to sync them, maybe even do a script for a celebration mode Tesla like ahah so more is coming than what I have now in my git.
As for my desks they are new here in my country at least, they are from IKEA, the MITTZON series, I believe there are 2 models 60 and 80 cm deep, I own the 80mm deep ones so I can only confirm that these use Jiecang hardware and they support the protocol via the RJ-12 port with no issues, just make sure to use the deskās provided ground and not just wtv power supply you have for testing. For future compatibility itās worth pointing out that my desks were bought the current year of 2024, future desks might look the same but with different hardware, who knows?
For users following the IKEA assembly instructions just make sure to pass half of a telephone cable like you did with the controller through the desks cable holes and connect to the F connector, BEFORE YOU ASSEMBLE THE TOP!!!
Now about the RJ-45 port. If your goal is to completely upgrade the standard controls of the desk or just to reverse engineer the desk as you did yeah this is the correct port to use. If you donāt and just want to add wireless remote control and status report I think this is not the best option and should be avoided if your desk has the RJ12 port and this one works with the cmd you want to use. I have several concerns with the RJ45 approach:
1st - Warranty: my desks come with 10 years of warranty, so causing damage to any part of the desk is not an option.
2nd - Safety: I havenāt read everything on this forum since at this time I am a little busy but from my understanding you guys managed to control the desk without soft-stop, if I understand this right this could mean that the handset has like a āLower Levelā access to the deskās controls, for exemple I havenāt managed to move the desk via the RJ12 connect without soft stop, so I suspect the RJ12 port has some kind of user error protection or at least is already designed by the manufacturer for remote access, in order for you guys to fix this again if my understanding is correct, you would need to make some sort of controller that could move the desk to a desired height but the desk already provides this for you. And I hope that the RJ45 port doesnāt let you send the desk higher or lower than possible, from my limited testing the RJ12 port doesnāt let you do nothing of those sorts.
3rd - Practicality: if your desk already provides a connector that is not in use itās just more practical to go to the store, get a telephone cable and cut it in half, than to make a RJ45 adapter sniffer and put it between desk components. All I used is a raspberry pi pico w ~7ā¬ and a standard telephone cable ~1ā¬ maybe, 10ā¬ max for the setup, all standard stuff fast to connect and go.
4th - Service Reliability: well this is pretty easy to understand, if you keep the standard controls connected always, you donāt loose your deskās functionality while tinkering with stuff, this is especially important if the desk in question is not used by you, but used by others, like your wife/husband/girlfriend/boyfriend.
Hi @pereira98, I definitely see all the benefits with your approach and agree with all of your comments. Itās simpler to wire, requires less hardware, and like you said it just seems like a better overall way to interface. I was initially keen to do what you did but didnāt know how to get the commands;)
Iām happy to help do some testing.
I have my test rig set up and will chip away at it over the coming days/weeks.
I donāt believe all desks have an rj12 port though. So some may still need a pass through set-up.
Next Iāll review where your code is up to and try to get a go to height command working. And Iām also interested whether we can get a height sensor going without using a custom component or custom sensor, perhaps by using this approach.
Well in cases like this, you can easily decompile an apk online but if you want more options and a more professional tool, maybe try Ghidra brought to us by NSA. The base tools that these use I think its mostly Apktool I think Im not sure but then just go throgh the filesystem trying to understand how everything works.
I tested a Go to specific height X feature like this, and it worked quite well soft start/stop is nice. Where is your implementation of this - maybe I missed it. ta.
button:
- platform: template
name: "Go to specific height X"
on_press:
then:
- uart.write:
id: uart_bus2
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 as the sum of specific bytes modulo 256
bArr[7] = 0x7E;
return bArr;
number:
- platform: template
name: "Go To Height cm"
id: go_to_height_value
optimistic: true
min_value: 0.0
max_value: 1000.0
step: 0.1
Edit: And this seems to work ok as a height sensor.
uart:
- id: uart_bus2
tx_pin: GPIO19
rx_pin: GPIO18
baud_rate: 9600
debug:
direction: BOTH
dummy_receiver: true
after:
timeout: 10ms
sequence:
- lambda: |-
UARTDebug::log_int(direction, bytes, ',');
ESP_LOGD("custom", "Bytes size: %d", bytes.size());
if (direction == UART_DIRECTION_TX) {
if (bytes.size() == 9) {
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
I donāt have my ESHhome config online since itās mainly Rocka84ās config, I didnāt spend much time on this besides decompiling the deskās app yet Thatās why I also added his repository link to the GitLab readme.
Nice Iām glad that works since itās probably one of the most important commands.
Thanks. Iām still reviewing Rocka84ās project. I didnāt know about it until you flagged it. It seems quite comprehensive.
I may produce and test a very minimal yaml only project based on it and publish it here that users can more easily adapt if they want/need. And then point them to the project if they want more features.
Hi!
Rocka84 here
Before you spent to much time on my project you linked above, I wanted to let you that I deprecated it shortly after it was done just to reimplement it again slightly differently
The new code is implemented as an ESPHome Component: esphome_components/components/jiecang_desk_controller at master Ā· Rocka84/esphome_components Ā· GitHub
Here is an example how itās used: esphome_components/example_jiecang_desk_controller.yaml at master Ā· Rocka84/esphome_components Ā· GitHub
Itās basically the same approach but implemented in a (I hope) more future proof way. And itās easier to install as the component is served via github.
Nice. Thanks for getting back to us.
Iāll have a tinker over the coming days. I might detail some instructions on how to build the rj12 dongle (for newbies) and youāre welcome to add that to your project etc.
Iāll probably link to your project as a preferred option for those with a rj12 port once Iāve done testing etc.
Wow! I feel a bit honored
I didnāt announce the project because Iām not sure if itās better or worse than the multiple alternatives. But Iām happy you found it and seem to like it
This motivates me to add some photos of the little dongle I created to the readme after work. I have also created a case design with onshape that I could link from there.
Hello again!
tl;dr: new: number entities, recommended config here.
Inspired by the project actually being used I spent some time on it this weekend
Thanks to the information collected by Mahko_Mahko I was able to add two essential commands to my project.
Stop command
It is now possible to add a stop button and/or use the stop()
command in lambdas. In my case the desk stops immediately, so no soft stop unfortunately. (I guess itās like an emergency break so itās for security reasons?)
Go to specified height
There now is a method goto_height(float height)
to specify a height in centimeters that the desk will then move to. This enabled the next new feature.
Number entities
Starting with the current height of the desk I added number entities which allow to show and control a numeric value.
In other words you can now use a numeric input to control the height of the desk!
I plan to implement this for other values too like the height in percent or the stored positions.
Everything is still optional and all previous features are still available. So you can choose to use numbers, sensors, buttons and/or lambdas in any combination.
You can find a full blown example config here.
A recommended config is also available.
Let me know what you think! Here or via GitHub Issues!
Thanks for sharing. I have been tinkering with this but I seem to be getting plauged by weird issues which I think relate to cheap RJ12 cables and cheap D1 miniāsā¦ Still working through it.
@pereira98 gets the credit for a lot of that info.
Hereās my bare bones āyaml onlyā version.
People getting started can try this as a basic implementation if they like, and move over to yours for more advanced features.
Two goals:
- Make it easy for newbies to get started (although my weird board config might confuse some)
- Make it easy for beginners to tweak the sensor if needed (weāve had some different protocol variants pop up and this reduces reliance on cpp developers).
Feel free to borrow the pics etc. I would have done it with a D1 mini to keep it simple for people but my d1 miniās are dodgy and I had a spare C3.
Config
# 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]
Hello together!
iĀ“m very new to ESPHome and HomeAssistant but i am very interested to learn it. I own a Loxone Smarthome and have everything automated via Loxone and ioBroker. On the other side there is a HomeAssistant that i use for testing some things and i want to integrate my Ergotopia Desktopia Pro to this with this project here.
As i said, iĀ“m totally new and just installed ESPHome to HomeAssistant. I worked allready with some Wemos D1 mini and have some projects running with other firmware.
Can someone tell me how i should start? Is there a good tutorial? What should i really solder and what YAML and code should i use for this desk?
Here are very much information and i am a little bit confused Maybe someone have fun to help me out via Chat or something, so that we donĀ“t spam this thread more I would really like it! IĀ“m from germany so if youre from germany too we can also speak / write in german.
Thank you, David
Hi @solution3,
a quick search revelead this: Desktopia Pro X Smart Control
I didnāt read all of it yet but it sure looks like your desk is using a jiecang controller
So you may use one of the solutions here that use the RJ12 port.
My solution (see above) should work for the basic features like the height sensor and most buttons. But Iām not sure about all features.
But @Mahko_Mahkoās latest suggestion is more flexible. If you want to use parts of the protocol that are different for your desk from what I implemented, his solution is easier to adapt to your needs.
For getting started on esphome in general you can find a ton of information on Google or YouTube.
btw: I am from Germany but I prefer keeping this conversation in english and public to have the information accessible to as many people as possible.