From b851b63f2c600943683929549822437f45b2ede7 Mon Sep 17 00:00:00 2001 From: ElVit Date: Tue, 23 Jul 2024 15:59:21 +0200 Subject: [PATCH] Modified to work with maidsite --- .gitignore | 2 +- .vimrc | 4 - README.md | 12 +- components/jiecang_desk_controller/README.md | 184 --------- .../jiecang_desk_controller/__init__.py | 174 -------- .../jiecang_desk_controller.cpp | 314 --------------- .../jiecang_desk_controller.h | 98 ----- .../jiecang_desk_number.cpp | 32 -- .../jiecang_desk_number.h | 33 -- components/maidsite_desk_controller/README.md | 198 +++++++++ .../maidsite_desk_controller/__init__.py | 184 +++++++++ .../example_basic.yaml | 57 +-- .../example_full.yaml | 110 ++--- .../maidsite_desk_controller.cpp | 381 ++++++++++++++++++ .../maidsite_desk_controller.h | 105 +++++ .../maidsite_desk_number.cpp | 37 ++ .../maidsite_desk_number.h | 35 ++ .../stl/D1mini Case Bottom.stl | Bin .../stl/D1mini Case Clamp.stl | Bin .../stl/D1mini Case Table Clamp A.stl | Bin .../stl/D1mini Case Table Clamp B.stl | Bin .../stl/D1mini Case Top.stl | Bin example_jiecang_desk_controller.yaml | 1 - example_maidsite_desk_controller.yaml | 1 + 24 files changed, 1039 insertions(+), 923 deletions(-) delete mode 100644 .vimrc delete mode 100644 components/jiecang_desk_controller/README.md delete mode 100644 components/jiecang_desk_controller/__init__.py delete mode 100644 components/jiecang_desk_controller/jiecang_desk_controller.cpp delete mode 100644 components/jiecang_desk_controller/jiecang_desk_controller.h delete mode 100644 components/jiecang_desk_controller/jiecang_desk_number.cpp delete mode 100644 components/jiecang_desk_controller/jiecang_desk_number.h create mode 100644 components/maidsite_desk_controller/README.md create mode 100644 components/maidsite_desk_controller/__init__.py rename components/{jiecang_desk_controller => maidsite_desk_controller}/example_basic.yaml (57%) rename components/{jiecang_desk_controller => maidsite_desk_controller}/example_full.yaml (54%) create mode 100644 components/maidsite_desk_controller/maidsite_desk_controller.cpp create mode 100644 components/maidsite_desk_controller/maidsite_desk_controller.h create mode 100644 components/maidsite_desk_controller/maidsite_desk_number.cpp create mode 100644 components/maidsite_desk_controller/maidsite_desk_number.h rename components/{jiecang_desk_controller => maidsite_desk_controller}/stl/D1mini Case Bottom.stl (100%) rename components/{jiecang_desk_controller => maidsite_desk_controller}/stl/D1mini Case Clamp.stl (100%) rename components/{jiecang_desk_controller => maidsite_desk_controller}/stl/D1mini Case Table Clamp A.stl (100%) rename components/{jiecang_desk_controller => maidsite_desk_controller}/stl/D1mini Case Table Clamp B.stl (100%) rename components/{jiecang_desk_controller => maidsite_desk_controller}/stl/D1mini Case Top.stl (100%) delete mode 120000 example_jiecang_desk_controller.yaml create mode 100644 example_maidsite_desk_controller.yaml diff --git a/.gitignore b/.gitignore index 59ee0a5..9afcb24 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -**/__pycache__/** +**/__pycache__/** diff --git a/.vimrc b/.vimrc deleted file mode 100644 index 00f4114..0000000 --- a/.vimrc +++ /dev/null @@ -1,4 +0,0 @@ -if SpmSetProject("esphome_components") == 0 - nmap h yy'fpwd2f:f)lC;==mf^w - nmap s 02w"aye2b02w"byej/::a Vf{%jd/::b f{%jpzz^wj -endif diff --git a/README.md b/README.md index dff4597..c0e1f5b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rocka84's ESPHome Components - -## Available Components - -* [Jiecang Desk Controller](components/jiecang_desk_controller/) - +# ElVit's ESPHome Components + +## Available Components + +* [Maidsite Desk Controller](components/maidsite_desk_controller/) + diff --git a/components/jiecang_desk_controller/README.md b/components/jiecang_desk_controller/README.md deleted file mode 100644 index 73386a0..0000000 --- a/components/jiecang_desk_controller/README.md +++ /dev/null @@ -1,184 +0,0 @@ -# ESPHome Jiecang Desk Controller - -[ESPHome](https://esphome.io/) component for controlling Jiecang desk controllers via their serial protocol. - -![](https://github.com/Rocka84/esphome_components/assets/2353088/b04d1fd7-d0ed-443d-87b7-87454757c0f0) - -Attention: I only have one [RJ12 model](https://www.jiecang.com/product/jcb35m11c.html) to test this -but it's likely that other Jiecang controllers are supported as their serial protocol should be compatible. - -## Usage - -### What you need - -* ESPHome compatible microcontroller -* depending on your model of desk controller - * cable with RJ12 connector (phone cable, RJ11 may also work) - * cable with RJ45 connector (network cable) - -### Wiring - -#### RJ12 - -Please double check this for your specific model! - -pin | function -----|--------- - 1 | NC (pulled up) - 2 | GND - 3 | TX - 4 | VCC - 5 | RX - 6 | NC (pulled up) - -#### RJ45 - -**Untested** and only for reference! - -pin | function -----|--------- - 1 | HS3 [^1] - 2 | TX - 3 | GND - 4 | RX - 5 | VCC - 6 | HS2 [^1] - 7 | HS1 [^1] - 8 | HS0 [^1] - -[^1]: not used here - -#### microcontroller - -ESP | desk -----|----- -GND | GND -5V | VCC -RX | TX -TX | RX - -![](https://github.com/Rocka84/esphome_components/assets/2353088/39e08774-a215-4e7e-8345-a2acafce28a2) - -## Usage - -```yaml -esphome: - ... - on_boot: - # This script is required to initialize the following sensors: - # height_pct, height_min, height_max, position1 - position4 - # You can skip this if you don't use those. - priority: 0 # when mostly everything else is done - then: - - lambda: "id(my_desk).request_physical_limits();" - - delay: 0.1s - - lambda: "id(my_desk).request_limits();" - - delay: 0.1s - - lambda: "id(my_desk).request_settings();" - -external_components: - - source: - type: git - url: https://github.com/Rocka84/esphome_components/ - components: [ jiecang_desk_controller ] - -uart: - id: uart_bus - tx_pin: TX - rx_pin: RX - baud_rate: 9600 - -logger: - baud_rate: 0 # disable logging over uart, required when using the RX/TX pins for the controller - -jiecang_desk_controller: - id: my_desk - sensors: - height: - name: "Height" - numbers: - height: - name: "Height" - buttons: - move_up: - name: "Move up" - move_down: - name: "Move down" - stop: - name: "Stop" - position1: - name: "Position 1" - -button: - - platform: template - name: "Step down" - on_press: - lambda: "id(my_desk).goto_height(84.0);" -``` - -### Examples - -* basic, sufficient for most people: [example_basic.yaml](example_basic.yaml) -* full with all features in use: [example_full.yaml](example_full.yaml) - -### Features - -#### sensors - -sensor | description ------------|---------------------------- -height | current height of the desk -height_pct | height in percent -height_min | minimal height -height_max | maximal height -position1 | 1st stored height -position2 | 2nd stored height -position3 | 3rd stored height -position4 | 4th stored height - -#### number entities - -Hold current values read from the desk and set values to desk when changed. - -sensor | description ------------|---------------------------- -height | current height of the desk - - -#### buttons - -button | description ---------------|--------------------------- -step_up | move up desk by one step (~14mm) -step_down | move down desk by one step (~14mm) -move_up | move up until stopped -move_down | move down until stopped -stop | stop movement of desk -position1 | move to 1st stored height -position2 | move to 2nd stored height -position3 | move to 3rd stored height -position4 | move to 4th stored height -save_position | press position button afterwards to store current height to that position - -#### lambda methods - -lambda method | description -----------------------------------|--------------------------- -`id(my_desk).step_up()` | step_up desk by one step (~14mm) -`id(my_desk).step_down()` | step_down desk by one step (~14mm) -`id(my_desk).move_up()` | move up -`id(my_desk).move_down()` | move down -`id(my_desk).stop()` | stop movement of desk -`id(my_desk).goto_position(pos)` | move to stored height `pos` -`id(my_desk).save_position(pos)` | save current height to position `pos` -`id(my_desk).goto_height(height)` | move to specified height - -## Case - -You can find a 3D-printable case in the [stl folder](stl/) or on [onshape](https://cad.onshape.com/documents/9619b6e4e11b26a3e9d82630/w/ca8259951d8b6bb3513992f7/e/2aa1144a31e5b4c252a13681?renderMode=0&uiState=665987de1c1f4a6c5d2d97a4). - -## Sources - -Thanks to [phord/Jarvis](https://github.com/phord/Jarvis) for reverse engineering the UART interface and most control messages! -Thanks to [OkhammahkO](https://github.com/OkhammahkO) for collecting the scattered information at [pimp-my-desk/desk-control](https://gitlab.com/pimp-my-desk/desk-control) and for his work in the home assistant community! - diff --git a/components/jiecang_desk_controller/__init__.py b/components/jiecang_desk_controller/__init__.py deleted file mode 100644 index f0ec16d..0000000 --- a/components/jiecang_desk_controller/__init__.py +++ /dev/null @@ -1,174 +0,0 @@ -import esphome.codegen as cg -import esphome.config_validation as cv -from esphome import pins -from esphome.components import uart, sensor, button, number -from esphome.const import CONF_ID, CONF_HEIGHT, CONF_UNIT_OF_MEASUREMENT, CONF_ACCURACY_DECIMALS, UNIT_CENTIMETER, UNIT_PERCENT - -DEPENDENCIES = ['uart'] -AUTO_LOAD = ['sensor', 'button', 'number'] - -jiecang_desk_controller_ns = cg.esphome_ns.namespace('jiecang_desk_controller') - -JiecangDeskController = jiecang_desk_controller_ns.class_('JiecangDeskController', cg.Component, uart.UARTDevice) -JiecangDeskButton = jiecang_desk_controller_ns.class_('JiecangDeskButton', button.Button, cg.Component) -JiecangDeskNumber = jiecang_desk_controller_ns.class_('JiecangDeskNumber', number.Number, cg.Component) - - -CONF_SENSORS = "sensors" -CONF_BUTTONS = "buttons" -CONF_NUMBERS = "numbers" -CONF_UNIT = "unit" -CONF_STEP_UP = "step_up" -CONF_STEP_DOWN = "step_down" -CONF_STOP = "stop" -CONF_HEIGHT_MIN = "height_min" -CONF_HEIGHT_MAX = "height_max" -CONF_HEIGHT_PCT = "height_pct" -CONF_POSITION1 = "position1" -CONF_POSITION2 = "position2" -CONF_POSITION3 = "position3" -CONF_POSITION4 = "position4" -CONF_SAVE_POSITION = "save_position" -CONF_MOVE_UP = "move_up" -CONF_MOVE_DOWN = "move_down" - - -button_constants = {} -button_constants[CONF_STEP_UP] = 0 -button_constants[CONF_STEP_DOWN] = 1 -button_constants[CONF_STOP] = 2 -button_constants[CONF_POSITION1] = 3 -button_constants[CONF_POSITION2] = 4 -button_constants[CONF_POSITION3] = 5 -button_constants[CONF_POSITION4] = 6 -button_constants[CONF_SAVE_POSITION] = 7 -button_constants[CONF_MOVE_UP] = 8 -button_constants[CONF_MOVE_DOWN] = 9 - -# Backward compatibility -CONF_RAISE = "raise" -CONF_LOWER = "lower" -button_constants[CONF_RAISE] = button_constants[CONF_STEP_UP] -button_constants[CONF_LOWER] = button_constants[CONF_STEP_DOWN] - - -number_constants = {} -number_constants[CONF_HEIGHT] = 0 -number_constants[CONF_HEIGHT_PCT] = 1 - -CONFIG_SCHEMA = cv.COMPONENT_SCHEMA.extend({ - cv.GenerateID(): cv.declare_id(JiecangDeskController), - cv.Optional(CONF_SENSORS): cv.Schema({ - cv.Optional(CONF_HEIGHT): sensor.sensor_schema( - accuracy_decimals = 1, - unit_of_measurement = UNIT_CENTIMETER - ), - cv.Optional(CONF_UNIT): sensor.sensor_schema( - accuracy_decimals = 0 - ), - cv.Optional(CONF_HEIGHT_PCT): sensor.sensor_schema( - accuracy_decimals = 1, - unit_of_measurement = UNIT_PERCENT - ), - cv.Optional(CONF_HEIGHT_MIN): sensor.sensor_schema( - accuracy_decimals = 1, - unit_of_measurement = UNIT_CENTIMETER - ), - cv.Optional(CONF_HEIGHT_MAX): sensor.sensor_schema( - accuracy_decimals = 1, - unit_of_measurement = UNIT_CENTIMETER - ), - cv.Optional(CONF_POSITION1): sensor.sensor_schema( - accuracy_decimals = 1, - unit_of_measurement = UNIT_CENTIMETER - ), - cv.Optional(CONF_POSITION2): sensor.sensor_schema( - accuracy_decimals = 1, - unit_of_measurement = UNIT_CENTIMETER - ), - cv.Optional(CONF_POSITION3): sensor.sensor_schema( - accuracy_decimals = 1, - unit_of_measurement = UNIT_CENTIMETER - ), - cv.Optional(CONF_POSITION4): sensor.sensor_schema( - accuracy_decimals = 1, - unit_of_measurement = UNIT_CENTIMETER - ), - }), - cv.Optional(CONF_NUMBERS): cv.Schema({ - cv.Optional(CONF_HEIGHT): number.NUMBER_SCHEMA.extend({ - cv.GenerateID(): cv.declare_id(JiecangDeskNumber), - cv.Optional(CONF_ACCURACY_DECIMALS, default=1): cv.int_, - cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_CENTIMETER): cv.string, - }), - cv.Optional(CONF_HEIGHT_PCT): number.NUMBER_SCHEMA.extend({ - cv.GenerateID(): cv.declare_id(JiecangDeskNumber), - cv.Optional(CONF_ACCURACY_DECIMALS, default=1): cv.int_, - cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_PERCENT): cv.string, - }), - }), - cv.Optional(CONF_BUTTONS): cv.Schema({ - cv.Optional(CONF_STEP_UP): button.BUTTON_SCHEMA.extend({cv.GenerateID(): cv.declare_id(JiecangDeskButton)}), - cv.Optional(CONF_STEP_DOWN): button.BUTTON_SCHEMA.extend({cv.GenerateID(): cv.declare_id(JiecangDeskButton)}), - cv.Optional(CONF_STOP): button.BUTTON_SCHEMA.extend({cv.GenerateID(): cv.declare_id(JiecangDeskButton)}), - cv.Optional(CONF_POSITION1): button.BUTTON_SCHEMA.extend({cv.GenerateID(): cv.declare_id(JiecangDeskButton)}), - cv.Optional(CONF_POSITION2): button.BUTTON_SCHEMA.extend({cv.GenerateID(): cv.declare_id(JiecangDeskButton)}), - cv.Optional(CONF_POSITION3): button.BUTTON_SCHEMA.extend({cv.GenerateID(): cv.declare_id(JiecangDeskButton)}), - cv.Optional(CONF_POSITION4): button.BUTTON_SCHEMA.extend({cv.GenerateID(): cv.declare_id(JiecangDeskButton)}), - cv.Optional(CONF_SAVE_POSITION): button.BUTTON_SCHEMA.extend({cv.GenerateID(): cv.declare_id(JiecangDeskButton)}), - cv.Optional(CONF_MOVE_UP): button.BUTTON_SCHEMA.extend({cv.GenerateID(): cv.declare_id(JiecangDeskButton)}), - cv.Optional(CONF_MOVE_DOWN): button.BUTTON_SCHEMA.extend({cv.GenerateID(): cv.declare_id(JiecangDeskButton)}), - # Backward compatibility - cv.Optional(CONF_RAISE): button.BUTTON_SCHEMA.extend({cv.GenerateID(): cv.declare_id(JiecangDeskButton)}), - cv.Optional(CONF_LOWER): button.BUTTON_SCHEMA.extend({cv.GenerateID(): cv.declare_id(JiecangDeskButton)}), - }), -}).extend(uart.UART_DEVICE_SCHEMA) - -async def to_code(config): - var = cg.new_Pvariable(config[CONF_ID]) - await cg.register_component(var, config) - await uart.register_uart_device(var, config) - - if CONF_SENSORS in config: - sensors = config[CONF_SENSORS] - - if CONF_HEIGHT in sensors: - sens = await sensor.new_sensor(sensors[CONF_HEIGHT]) - cg.add(var.set_sensor_height(sens)) - if CONF_UNIT in sensors: - sens = await sensor.new_sensor(sensors[CONF_UNIT]) - cg.add(var.set_sensor_unit(sens)) - if CONF_HEIGHT_MIN in sensors: - sens = await sensor.new_sensor(sensors[CONF_HEIGHT_MIN]) - cg.add(var.set_sensor_height_min(sens)) - if CONF_HEIGHT_MAX in sensors: - sens = await sensor.new_sensor(sensors[CONF_HEIGHT_MAX]) - cg.add(var.set_sensor_height_max(sens)) - if CONF_HEIGHT_PCT in sensors: - sens = await sensor.new_sensor(sensors[CONF_HEIGHT_PCT]) - cg.add(var.set_sensor_height_pct(sens)) - if CONF_POSITION1 in sensors: - sens = await sensor.new_sensor(sensors[CONF_POSITION1]) - cg.add(var.set_sensor_position1(sens)) - if CONF_POSITION2 in sensors: - sens = await sensor.new_sensor(sensors[CONF_POSITION2]) - cg.add(var.set_sensor_position2(sens)) - if CONF_POSITION3 in sensors: - sens = await sensor.new_sensor(sensors[CONF_POSITION3]) - cg.add(var.set_sensor_position3(sens)) - if CONF_POSITION4 in sensors: - sens = await sensor.new_sensor(sensors[CONF_POSITION4]) - cg.add(var.set_sensor_position4(sens)) - - if CONF_BUTTONS in config: - buttons = config[CONF_BUTTONS] - for button_type in buttons.keys(): - btn = await button.new_button(buttons[button_type]) - cg.add(var.add_button(btn, button_constants[button_type])) - - if CONF_NUMBERS in config: - numbers = config[CONF_NUMBERS] - for number_type in numbers.keys(): - num = await number.new_number(numbers[number_type], min_value=0, max_value=100, step=.1) - cg.add(var.add_number(num, number_constants[number_type])) - diff --git a/components/jiecang_desk_controller/jiecang_desk_controller.cpp b/components/jiecang_desk_controller/jiecang_desk_controller.cpp deleted file mode 100644 index 225f0d1..0000000 --- a/components/jiecang_desk_controller/jiecang_desk_controller.cpp +++ /dev/null @@ -1,314 +0,0 @@ -#include "jiecang_desk_controller.h" -#include "esphome/core/log.h" - -namespace esphome { - namespace jiecang_desk_controller { - - static const char *const TAG = "jiecang_desk_controller"; - - float JiecangDeskController::byte2float(int high, int low) { - return static_cast((high<<8) + low)/10; - } - - bool JiecangDeskController::bufferMessage(int data, unsigned int *buffer, int len) { - // This is a very simple method of receiving messages from the desk. - // It will fail on messages that contain the value 0x7E in their payload. - // But it is super simple and works for the messages we care about. - - // format: 0xF2 0xF2 [command] [param_count] [[param] ...] [checksum] 0x7E - // checksum: sum of [command], [param_count] and all [param]s - - static int cmd_incoming = 0; // 0: wait for F2, 1: wait for 2nd F2, 2: buffer data - static int pos = 0; - - if (cmd_incoming < 2 && data == 0xF2) { // start of message, must appear twice - cmd_incoming++; - pos = 0; - - } else if (cmd_incoming == 1) { // no second F2 received - cmd_incoming = 0; - - } else if (cmd_incoming == 2) { - if (data == 0x7E) { // end of message - cmd_incoming = 0; - for (;pos= len) { // message too long, drop it - cmd_incoming = 0; - - } else { - buffer[pos++] = data; // buffer data - } - - } // else: received garbage - - return false; - } - - void JiecangDeskController::handleMessage(unsigned int *message) { - // ESP_LOGV("jiecang_desk_controller", "message %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", message[0], message[1], message[2], message[3], message[4], message[5], message[6], message[7], message[8], message[9]); - - switch (message[0]) { - case 0x01: - ESP_LOGV("jiecang_desk_controller", "height 0x%0X%0X", message[2], message[3]); - float new_height; - new_height = byte2float(message[2], message[3]); - if (new_height == current_height) return; - current_height = new_height; - if (height != nullptr) height->publish_state(current_height); - if (number_height != nullptr) number_height->publish_state(current_height); - - if (height_pct != nullptr && limit_max != 0) - height_pct->publish_state((current_height - limit_min) / (limit_max - limit_min) * 100); - if (number_height_pct != nullptr && limit_max != 0) - number_height_pct->publish_state(roundf((current_height - limit_min) / (limit_max - limit_min) * 1000)/10); - break; - - case 0x20: - ESP_LOGV("jiecang_desk_controller", "limits 0x%0X max %i min %i", message[2], (message[2] & 1), (message[2]>>4)); - - if ((message[2] & 1) == 0) { // low nibble 0 -> no max limit, use physical_max - limit_max = physical_max; - if (height_max != nullptr) height_max->publish_state(limit_max); - if (number_height != nullptr) number_height->set_max_value(limit_max); - } - if ((message[2]>>4) == 0) { // high nibble 0 -> no min limit, use physical_min - limit_min = physical_min; - if (height_min != nullptr) height_min->publish_state(limit_min); - if (number_height != nullptr) number_height->set_min_value(limit_min); - } - break; - - case 0x07: - ESP_LOGV("jiecang_desk_controller", "physical limits 0x%02X%02X 0x%02X%02X", message[2], message[3], message[4], message[5]); - physical_max = byte2float(message[2], message[3]); - physical_min = byte2float(message[4], message[5]); - break; - - case 0x21: - ESP_LOGV("jiecang_desk_controller", "height_max 0x%02X%02X", message[2], message[3]); - limit_max = byte2float(message[2], message[3]); - if (height_max != nullptr) height_max->publish_state(limit_max); - if (number_height != nullptr) number_height->set_max_value(limit_max); - break; - - case 0x22: - ESP_LOGV("jiecang_desk_controller", "height_min 0x%02X%02X", message[2], message[3]); - limit_min = byte2float(message[2], message[3]); - if (height_min != nullptr) height_min->publish_state(limit_min); - if (number_height != nullptr) number_height->set_min_value(limit_min); - break; - - case 0x25: - ESP_LOGV("jiecang_desk_controller", "position1 0x%02X%02X", message[2], message[3]); - if (position1 != nullptr) position1->publish_state(byte2float(message[2], message[3])); - break; - - case 0x26: - ESP_LOGV("jiecang_desk_controller", "position2 0x%02X%02X", message[2], message[3]); - if (position2 != nullptr) position2->publish_state(byte2float(message[2], message[3])); - break; - - case 0x27: - ESP_LOGV("jiecang_desk_controller", "position3 0x%02X%02X", message[2], message[3]); - if (position3 != nullptr) position3->publish_state(byte2float(message[2], message[3])); - break; - - case 0x28: - ESP_LOGV("jiecang_desk_controller", "position4 0x%02X%02X", message[2], message[3]); - if (position4 != nullptr) position4->publish_state(byte2float(message[2], message[3])); - break; - - default: - ESP_LOGV("jiecang_desk_controller", "unknown message %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", message[0], message[1], message[2], message[3], message[4], message[5], message[6], message[7], message[8], message[9]); - } - } - - void JiecangDeskController::update() { - const int max_length = 10; - static unsigned int buffer[max_length]; - while (available()) { - if(bufferMessage(read(), buffer, max_length)) { - handleMessage(buffer); - } - } - } - - void JiecangDeskController::send_simple_command(unsigned char cmd) { - write_array({ 0xF1, 0xF1, cmd, 0x00, cmd, 0x7E }); - } - - void JiecangDeskController::add_button(button::Button *btn, int action) { - btn->add_on_press_callback([this, action]() { this->button_press_action(action); }); - } - - void JiecangDeskController::step_up() { - send_simple_command(0x01); - } - - void JiecangDeskController::step_down() { - send_simple_command(0x02); - } - - void JiecangDeskController::stop() { - send_simple_command(0x2B); - } - - void JiecangDeskController::goto_position(int pos) { - switch (pos) { - case 1: - send_simple_command(0x05); - break; - case 2: - send_simple_command(0x06); - break; - case 3: - send_simple_command(0x27); - break; - case 4: - send_simple_command(0x28); - break; - } - } - - void JiecangDeskController::save_position(int pos) { - switch (pos) { - case 1: - send_simple_command(0x03); - break; - case 2: - send_simple_command(0x04); - break; - case 3: - send_simple_command(0x25); - break; - case 4: - send_simple_command(0x26); - break; - } - } - - void JiecangDeskController::goto_height(float height) { - unsigned char cmd = 0x1B; - unsigned char high_byte = ((int) height * 10) >> 8; - unsigned char low_byte = ((int) height * 10) & 0xFF; - - unsigned char checksum = cmd + 2 + high_byte + low_byte; - - write_array({ 0xF1, 0xF1, cmd, 0x02, high_byte, low_byte, checksum, 0x7E }); - } - - void JiecangDeskController::move_up() { - goto_height(limit_max); - } - - void JiecangDeskController::move_down() { - goto_height(limit_min); - } - - void JiecangDeskController::request_physical_limits() { - send_simple_command(0x0C); - } - - void JiecangDeskController::request_limits() { - send_simple_command(0x20); - } - - void JiecangDeskController::request_settings() { - send_simple_command(0x07); - } - - void JiecangDeskController::button_press_action(int action) { - ESP_LOGV("JiecangDeskController", "button_press_action %i", action); - switch (action) { - case BUTTON_STEP_UP: - step_up(); - break; - case BUTTON_STEP_DOWN: - step_down(); - break; - case BUTTON_STOP: - stop(); - save_position_mode = false; - break; - case BUTTON_MOVE_UP: - move_up(); - break; - case BUTTON_MOVE_DOWN: - move_down(); - break; - case BUTTON_POSITION1: - if (save_position_mode) { - save_position_mode = false; - save_position(1); - return; - } - goto_position(1); - break; - case BUTTON_POSITION2: - if (save_position_mode) { - save_position_mode = false; - save_position(2); - return; - } - goto_position(2); - break; - case BUTTON_POSITION3: - if (save_position_mode) { - save_position_mode = false; - save_position(3); - return; - } - goto_position(3); - break; - case BUTTON_POSITION4: - if (save_position_mode) { - save_position_mode = false; - save_position(4); - return; - } - goto_position(4); - break; - case BUTTON_SAVE_POSITION: - save_position_mode = true; - break; - } - } - - void JiecangDeskController::add_number(JiecangDeskNumber *number, int type) { - switch (type) { - case NUMBER_HEIGHT: - number_height = number; - break; - case NUMBER_HEIGHT_PCT: - number_height_pct = number; - number_height_pct->set_min_value(0); - number_height_pct->set_max_value(100); - break; - default: - return; - } - number->set_type(type); - number->set_parent(this); - } - - void JiecangDeskController::number_control(int type, float value) { - ESP_LOGV("JiecangDeskController", "number_control %i", type); - switch (type) { - case NUMBER_HEIGHT: - goto_height(value); - break; - case NUMBER_HEIGHT_PCT: - if (limit_max != 0) goto_height((limit_max - limit_min) * value / 100 + limit_min); - break; - } - } - - void JiecangDeskButton::press_action() {} - - } //namespace jiecang_desk_controller -} //namespace esphome - diff --git a/components/jiecang_desk_controller/jiecang_desk_controller.h b/components/jiecang_desk_controller/jiecang_desk_controller.h deleted file mode 100644 index 4f0a6ef..0000000 --- a/components/jiecang_desk_controller/jiecang_desk_controller.h +++ /dev/null @@ -1,98 +0,0 @@ -#pragma once - -#include -#include "esphome/core/component.h" -#include "esphome/components/sensor/sensor.h" -#include "esphome/components/button/button.h" -#include "esphome/components/uart/uart.h" -#include "esphome/core/hal.h" -#include "esphome/core/log.h" -#include "jiecang_desk_number.h" - -#define BUTTON_STEP_UP 0 -#define BUTTON_STEP_DOWN 1 -#define BUTTON_STOP 2 -#define BUTTON_POSITION1 3 -#define BUTTON_POSITION2 4 -#define BUTTON_POSITION3 5 -#define BUTTON_POSITION4 6 -#define BUTTON_SAVE_POSITION 7 -#define BUTTON_MOVE_UP 8 -#define BUTTON_MOVE_DOWN 9 - -#define NUMBER_HEIGHT 0 -#define NUMBER_HEIGHT_PCT 1 - -namespace esphome { - namespace jiecang_desk_controller { - - class JiecangDeskController : public PollingComponent, public sensor::Sensor, public uart::UARTDevice { - private: - float current_height = 0; - float limit_min = 0; - float limit_max = 0; - float physical_min = 0; - float physical_max = 0; - - bool save_position_mode = false; - - float byte2float(int high, int low); - bool bufferMessage(int data, unsigned int *buffer, int len); - void handleMessage(unsigned int *message); - - public: - void update() override; - - void set_sensor_height(sensor::Sensor *sensor) { this->height = sensor; } - void set_sensor_height_min(sensor::Sensor *sensor) { this->height_min = sensor; } - void set_sensor_height_max(sensor::Sensor *sensor) { this->height_max = sensor; } - void set_sensor_height_pct(sensor::Sensor *sensor) { this->height_pct = sensor; } - - void set_sensor_position1(sensor::Sensor *sensor) { this->position1 = sensor; } - void set_sensor_position2(sensor::Sensor *sensor) { this->position2 = sensor; } - void set_sensor_position3(sensor::Sensor *sensor) { this->position3 = sensor; } - void set_sensor_position4(sensor::Sensor *sensor) { this->position4 = sensor; } - - void send_simple_command(unsigned char cmd); - void add_button(button::Button *btn, int action); - void add_number(JiecangDeskNumber *number, int type); - - void step_up(); - void step_down(); - void stop(); - void goto_position(int pos); - void save_position(int pos); - void goto_height(float height); - void move_up(); - void move_down(); - - void request_physical_limits(); - void request_limits(); - void request_settings(); - - void number_control(int type, float value); - - protected: - Sensor *height{nullptr}; - Sensor *height_min{nullptr}; - Sensor *height_max{nullptr}; - Sensor *height_pct{nullptr}; - - Sensor *position1{nullptr}; - Sensor *position2{nullptr}; - Sensor *position3{nullptr}; - Sensor *position4{nullptr}; - - JiecangDeskNumber *number_height{nullptr}; - JiecangDeskNumber *number_height_pct{nullptr}; - - void button_press_action(int type); - }; - - class JiecangDeskButton : public Component, public button::Button { - protected: - void press_action() override; - }; - - } //namespace jiecang_desk_controller -} //namespace esphome diff --git a/components/jiecang_desk_controller/jiecang_desk_number.cpp b/components/jiecang_desk_controller/jiecang_desk_number.cpp deleted file mode 100644 index de15d91..0000000 --- a/components/jiecang_desk_controller/jiecang_desk_number.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "jiecang_desk_number.h" -#include "jiecang_desk_controller.h" -#include "esphome/core/log.h" - -namespace esphome { - namespace jiecang_desk_controller { - - static const char *const TAG = "jiecang_desk.number"; - - void JiecangDeskNumber::setup() {} - - void JiecangDeskNumber::dump_config() { - LOG_NUMBER("", "JiecangDeskNumber", this); - ESP_LOGCONFIG(TAG, " type %i", type); - } - - void JiecangDeskNumber::control(float value) { - this->publish_state(value); - parent->number_control(this->type, value); - } - - void JiecangDeskNumber::set_min_value(float value) { - traits.set_min_value(value); - } - - void JiecangDeskNumber::set_max_value(float value) { - traits.set_max_value(value); - } - - - } // namespace jiecang_desk_controller -} // namespace esphome diff --git a/components/jiecang_desk_controller/jiecang_desk_number.h b/components/jiecang_desk_controller/jiecang_desk_number.h deleted file mode 100644 index 72e0a5d..0000000 --- a/components/jiecang_desk_controller/jiecang_desk_number.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include "esphome/core/component.h" -#include "esphome/components/number/number.h" -#include "esphome/core/log.h" - -namespace esphome { - namespace jiecang_desk_controller { - - class JiecangDeskController; - - class JiecangDeskNumber : public number::Number, public Component { - private: - int type; - JiecangDeskController *parent; - - public: - void setup() override; - void dump_config() override; - - void set_parent(JiecangDeskController *parent) { this->parent = parent; } - void set_type(int type) { this->type = type; } - - void set_min_value(float value); - void set_max_value(float value); - - protected: - void control(float value) override; - - }; - - } // namespace jiecang_desk_controller -} // namespace esphome diff --git a/components/maidsite_desk_controller/README.md b/components/maidsite_desk_controller/README.md new file mode 100644 index 0000000..b3850b9 --- /dev/null +++ b/components/maidsite_desk_controller/README.md @@ -0,0 +1,198 @@ +# ESPHome Maidsite Desk Controller + +[ESPHome](https://esphome.io/) component for controlling Maidsite desk controllers via their serial protocol. + +![](https://github.com/Rocka84/esphome_components/assets/2353088/b04d1fd7-d0ed-443d-87b7-87454757c0f0) + +Attention: I only have one [RJ12 model](https://www.maidsite.com/product/jcb35m11c.html) to test this +but it's likely that other Maidsite controllers are supported as their serial protocol should be compatible. + +## Usage + +### What you need + +* ESPHome compatible microcontroller +* depending on your model of desk controller + * cable with RJ12 connector (phone cable, RJ11 may also work) + * cable with RJ45 connector (network cable) + +### Wiring + +#### RJ12 + +Please double check this for your specific model! + +pin | function +----|--------- + 1 | NC (pulled up) + 2 | GND + 3 | TX + 4 | VCC + 5 | RX + 6 | NC (pulled up) + +#### RJ45 + +**Untested** and only for reference! + +pin | function +----|--------- + 1 | HS3 [^1] + 2 | TX + 3 | GND + 4 | RX + 5 | VCC + 6 | HS2 [^1] + 7 | HS1 [^1] + 8 | HS0 [^1] + +[^1]: not used here + +#### microcontroller + +ESP | desk +----|----- +GND | GND +5V | VCC +RX | TX +TX | RX + +![](https://github.com/Rocka84/esphome_components/assets/2353088/39e08774-a215-4e7e-8345-a2acafce28a2) + +## Usage + +```yaml +esphome: + ... + on_boot: + # This script is required to initialize the following sensors: + # height_pct, height_min, height_max, position_m1 - position_m4 + # You can skip this if you don't use those. + priority: 0 # when mostly everything else is done + then: + - lambda: "id(my_desk).request_physical_limits();" + - delay: 0.1s + - lambda: "id(my_desk).request_limits();" + - delay: 0.1s + - lambda: "id(my_desk).request_settings();" + +external_components: + - source: + type: git + url: https://github.com/ElVit/esphome_maidsite_desk/ + components: [ maidsite_desk_controller ] + +uart: + - id: uart_bus + tx_pin: $pin_tx + rx_pin: $pin_rx + baud_rate: 9600 + +logger: + baud_rate: 0 # disable logging over uart, required when using the RX/TX pins for the controller + +maidsite_desk_controller: + id: my_desk + + sensors: + height_abs: + name: "Height" + + numbers: + height_abs: + name: "Height" + mode: SLIDER + + buttons: + stop: + name: "Stop" + step_up: + name: "Step up" + step_down: + name: "Step down" + goto_m1: + name: "Move to M1" + goto_m2: + name: "Move to M2" + goto_m3: + name: "Move to M3" + goto_m4: + name: "Move to M4" + +button: + - platform: template + name: "Step down" + on_press: + lambda: "id(my_desk).goto_height(84.0);" +``` + +### Examples + +* basic, sufficient for most people: [example_basic.yaml](example_basic.yaml) +* full with all features in use: [example_full.yaml](example_full.yaml) + +### Features + +#### sensors + +sensor | description +-------------|---------------------------- +height_abs | current height of the desk +height_pct | height in percent +height_min | minimal height +height_max | maximal height +position_m1 | 1st stored height +position_m2 | 2nd stored height +position_m3 | 3rd stored height +position_m4 | 4th stored height + +#### number entities + +Hold current values read from the desk and set values to desk when changed. + +sensor | description +------------|---------------------------- +height_abs | current height of the desk +height_pct | height in percent + +#### buttons + +button | description +-----------|--------------------------- +step_up | move up desk by one step (~14mm) +step_down | move down desk by one step (~14mm) +goto_max | move up until stopped +goto_min | move down until stopped +stop | stop movement of desk +goto_m1 | move to 1st stored height +goto_m2 | move to 2nd stored height +goto_m3 | move to 3rd stored height +goto_m4 | move to 4th stored height +save_m1 | save current height to 1th position +save_m2 | save current height to 2th position +save_m3 | save current height to 3th position +save_m4 | save current height to 4th position + +#### lambda methods + +lambda method | description +--------------------------------------|--------------------------- +`id(my_desk).step_up()` | step_up desk by one step (~14mm) +`id(my_desk).step_down()` | step_down desk by one step (~14mm) +`id(my_desk).goto_max_position()` | move up +`id(my_desk).goto_min_position()` | move down +`id(my_desk).stop()` | stop movement of desk +`id(my_desk).goto_mem_position(pos)` | move to stored height `pos` +`id(my_desk).save_mem_position(pos)` | save current height to position `pos` +`id(my_desk).goto_height(height)` | move to specified height + +## Case + +You can find a 3D-printable case in the [stl folder](stl/) or on [onshape](https://cad.onshape.com/documents/9619b6e4e11b26a3e9d82630/w/ca8259951d8b6bb3513992f7/e/2aa1144a31e5b4c252a13681?renderMode=0&uiState=665987de1c1f4a6c5d2d97a4). + +## Sources + +Thanks to [Rocka84](https://github.com/Rocka84/esphome_components) +Thanks to [phord/Jarvis](https://github.com/phord/Jarvis) for reverse engineering the UART interface and most control messages! +Thanks to [OkhammahkO](https://github.com/OkhammahkO) for collecting the scattered information at [pimp-my-desk/desk-control](https://gitlab.com/pimp-my-desk/desk-control) and for his work in the home assistant community! + diff --git a/components/maidsite_desk_controller/__init__.py b/components/maidsite_desk_controller/__init__.py new file mode 100644 index 0000000..43d9e42 --- /dev/null +++ b/components/maidsite_desk_controller/__init__.py @@ -0,0 +1,184 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import pins +from esphome.components import uart, sensor, button, number +from esphome.const import CONF_ID, CONF_UNIT_OF_MEASUREMENT, CONF_STEP, CONF_ACCURACY_DECIMALS, CONF_ENTITY_CATEGORY, UNIT_CENTIMETER, UNIT_PERCENT, ENTITY_CATEGORY_CONFIG + +DEPENDENCIES = ['uart'] +AUTO_LOAD = ['sensor', 'button', 'number'] + +maidsite_desk_controller_ns = cg.esphome_ns.namespace('maidsite_desk_controller') + +MaidsiteDeskController = maidsite_desk_controller_ns.class_('MaidsiteDeskController', cg.Component, uart.UARTDevice) +MaidsiteDeskButton = maidsite_desk_controller_ns.class_('MaidsiteDeskButton', button.Button, cg.Component) +MaidsiteDeskNumber = maidsite_desk_controller_ns.class_('MaidsiteDeskNumber', number.Number, cg.Component) + + +CONF_SENSORS = "sensors" +CONF_BUTTONS = "buttons" +CONF_NUMBERS = "numbers" +CONF_UNIT = "unit" +CONF_STEP_UP = "step_up" +CONF_STEP_DOWN = "step_down" +CONF_STOP = "stop" +CONF_GOTO_MAX = "goto_max" +CONF_GOTO_MIN = "goto_min" +CONF_HEIGHT_MIN = "height_min" +CONF_HEIGHT_MAX = "height_max" +CONF_HEIGHT_ABS = "height_abs" +CONF_HEIGHT_PCT = "height_pct" +CONF_POSITION_M1 = "position_m1" +CONF_POSITION_M2 = "position_m2" +CONF_POSITION_M3 = "position_m3" +CONF_POSITION_M4 = "position_m4" +CONF_GOTO_M1 = "goto_m1" +CONF_GOTO_M2 = "goto_m2" +CONF_GOTO_M3 = "goto_m3" +CONF_GOTO_M4 = "goto_m4" +CONF_SAVE_M1 = "save_m1" +CONF_SAVE_M2 = "save_m2" +CONF_SAVE_M3 = "save_m3" +CONF_SAVE_M4 = "save_m4" + +button_constants = {} +button_constants[CONF_STEP_UP] = 0 +button_constants[CONF_STEP_DOWN] = 1 +button_constants[CONF_STOP] = 2 +button_constants[CONF_GOTO_MAX] = 3 +button_constants[CONF_GOTO_MIN] = 4 +button_constants[CONF_GOTO_M1] = 5 +button_constants[CONF_GOTO_M2] = 6 +button_constants[CONF_GOTO_M3] = 7 +button_constants[CONF_GOTO_M4] = 8 +button_constants[CONF_SAVE_M1] = 9 +button_constants[CONF_SAVE_M2] = 10 +button_constants[CONF_SAVE_M3] = 11 +button_constants[CONF_SAVE_M4] = 12 + +number_constants = {} +number_constants[CONF_HEIGHT_ABS] = 0 +number_constants[CONF_HEIGHT_PCT] = 1 + +CONFIG_SCHEMA = cv.COMPONENT_SCHEMA.extend({ + cv.GenerateID(): cv.declare_id(MaidsiteDeskController), + + cv.Optional(CONF_SENSORS): cv.Schema({ + cv.Optional(CONF_UNIT): sensor.sensor_schema(accuracy_decimals = 0), + cv.Optional(CONF_HEIGHT_ABS): sensor.sensor_schema(accuracy_decimals = 1, unit_of_measurement = UNIT_CENTIMETER), + cv.Optional(CONF_HEIGHT_PCT): sensor.sensor_schema(accuracy_decimals = 1, unit_of_measurement = UNIT_PERCENT), + cv.Optional(CONF_HEIGHT_MIN): sensor.sensor_schema(accuracy_decimals = 1, unit_of_measurement = UNIT_CENTIMETER), + cv.Optional(CONF_HEIGHT_MAX): sensor.sensor_schema(accuracy_decimals = 1, unit_of_measurement = UNIT_CENTIMETER), + cv.Optional(CONF_POSITION_M1): sensor.sensor_schema(accuracy_decimals = 1, unit_of_measurement = UNIT_CENTIMETER), + cv.Optional(CONF_POSITION_M2): sensor.sensor_schema(accuracy_decimals = 1, unit_of_measurement = UNIT_CENTIMETER), + cv.Optional(CONF_POSITION_M3): sensor.sensor_schema(accuracy_decimals = 1, unit_of_measurement = UNIT_CENTIMETER), + cv.Optional(CONF_POSITION_M4): sensor.sensor_schema(accuracy_decimals = 1, unit_of_measurement = UNIT_CENTIMETER), + }), + cv.Optional(CONF_NUMBERS): cv.Schema({ + cv.Optional(CONF_HEIGHT_ABS): number.NUMBER_SCHEMA.extend({ + cv.GenerateID(): cv.declare_id(MaidsiteDeskNumber), + cv.Optional(CONF_ACCURACY_DECIMALS, default=1): cv.int_, + cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_CENTIMETER): cv.string, + cv.Optional(CONF_STEP, default=1): cv.float_, + }), + cv.Optional(CONF_HEIGHT_PCT): number.NUMBER_SCHEMA.extend({ + cv.GenerateID(): cv.declare_id(MaidsiteDeskNumber), + cv.Optional(CONF_ACCURACY_DECIMALS, default=1): cv.int_, + cv.Optional(CONF_UNIT_OF_MEASUREMENT, default=UNIT_PERCENT): cv.string, + cv.Optional(CONF_STEP, default=.1): cv.float_, + }), + }), + cv.Optional(CONF_BUTTONS): cv.Schema({ + cv.Optional(CONF_STEP_UP): button.BUTTON_SCHEMA.extend({ + cv.GenerateID(): cv.declare_id(MaidsiteDeskButton), + }), + cv.Optional(CONF_STEP_DOWN): button.BUTTON_SCHEMA.extend({ + cv.GenerateID(): cv.declare_id(MaidsiteDeskButton), + }), + cv.Optional(CONF_STOP): button.BUTTON_SCHEMA.extend({ + cv.GenerateID(): cv.declare_id(MaidsiteDeskButton), + }), + cv.Optional(CONF_GOTO_MAX): button.BUTTON_SCHEMA.extend({ + cv.GenerateID(): cv.declare_id(MaidsiteDeskButton), + }), + cv.Optional(CONF_GOTO_MIN): button.BUTTON_SCHEMA.extend({ + cv.GenerateID(): cv.declare_id(MaidsiteDeskButton), + }), + cv.Optional(CONF_GOTO_M1): button.BUTTON_SCHEMA.extend({ + cv.GenerateID(): cv.declare_id(MaidsiteDeskButton), + }), + cv.Optional(CONF_GOTO_M2): button.BUTTON_SCHEMA.extend({ + cv.GenerateID(): cv.declare_id(MaidsiteDeskButton), + }), + cv.Optional(CONF_GOTO_M3): button.BUTTON_SCHEMA.extend({ + cv.GenerateID(): cv.declare_id(MaidsiteDeskButton), + }), + cv.Optional(CONF_GOTO_M4): button.BUTTON_SCHEMA.extend({ + cv.GenerateID(): cv.declare_id(MaidsiteDeskButton), + }), + cv.Optional(CONF_SAVE_M1): button.BUTTON_SCHEMA.extend({ + cv.GenerateID(): cv.declare_id(MaidsiteDeskButton), + cv.Optional(CONF_ENTITY_CATEGORY, default=ENTITY_CATEGORY_CONFIG): cv.entity_category, + }), + cv.Optional(CONF_SAVE_M2): button.BUTTON_SCHEMA.extend({ + cv.GenerateID(): cv.declare_id(MaidsiteDeskButton), + cv.Optional(CONF_ENTITY_CATEGORY, default=ENTITY_CATEGORY_CONFIG): cv.entity_category, + }), + cv.Optional(CONF_SAVE_M3): button.BUTTON_SCHEMA.extend({ + cv.GenerateID(): cv.declare_id(MaidsiteDeskButton), + cv.Optional(CONF_ENTITY_CATEGORY, default=ENTITY_CATEGORY_CONFIG): cv.entity_category, + }), + cv.Optional(CONF_SAVE_M4): button.BUTTON_SCHEMA.extend({ + cv.GenerateID(): cv.declare_id(MaidsiteDeskButton), + cv.Optional(CONF_ENTITY_CATEGORY, default=ENTITY_CATEGORY_CONFIG): cv.entity_category, + }), + }), +}).extend(uart.UART_DEVICE_SCHEMA) + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) + + if CONF_SENSORS in config: + sensors = config[CONF_SENSORS] + + if CONF_UNIT in sensors: + sens = await sensor.new_sensor(sensors[CONF_UNIT]) + cg.add(var.set_sensor_unit(sens)) + if CONF_HEIGHT_MIN in sensors: + sens = await sensor.new_sensor(sensors[CONF_HEIGHT_MIN]) + cg.add(var.set_sensor_height_min(sens)) + if CONF_HEIGHT_MAX in sensors: + sens = await sensor.new_sensor(sensors[CONF_HEIGHT_MAX]) + cg.add(var.set_sensor_height_max(sens)) + if CONF_HEIGHT_ABS in sensors: + sens = await sensor.new_sensor(sensors[CONF_HEIGHT_ABS]) + cg.add(var.set_sensor_height(sens)) + if CONF_HEIGHT_PCT in sensors: + sens = await sensor.new_sensor(sensors[CONF_HEIGHT_PCT]) + cg.add(var.set_sensor_height_pct(sens)) + if CONF_POSITION_M1 in sensors: + sens = await sensor.new_sensor(sensors[CONF_POSITION_M1]) + cg.add(var.set_sensor_position_m1(sens)) + if CONF_POSITION_M2 in sensors: + sens = await sensor.new_sensor(sensors[CONF_POSITION_M2]) + cg.add(var.set_sensor_position_m2(sens)) + if CONF_POSITION_M3 in sensors: + sens = await sensor.new_sensor(sensors[CONF_POSITION_M3]) + cg.add(var.set_sensor_position_m3(sens)) + if CONF_POSITION_M4 in sensors: + sens = await sensor.new_sensor(sensors[CONF_POSITION_M4]) + cg.add(var.set_sensor_position_m4(sens)) + + if CONF_BUTTONS in config: + buttons = config[CONF_BUTTONS] + for button_type in buttons.keys(): + btn = await button.new_button(buttons[button_type]) + cg.add(var.add_button(btn, button_constants[button_type])) + + if CONF_NUMBERS in config: + numbers = config[CONF_NUMBERS] + for number_type in numbers.keys(): + num = await number.new_number(numbers[number_type], min_value=0, max_value=100, step=.1) + cg.add(var.add_number(num, number_constants[number_type])) + diff --git a/components/jiecang_desk_controller/example_basic.yaml b/components/maidsite_desk_controller/example_basic.yaml similarity index 57% rename from components/jiecang_desk_controller/example_basic.yaml rename to components/maidsite_desk_controller/example_basic.yaml index dc44217..1303ef0 100644 --- a/components/jiecang_desk_controller/example_basic.yaml +++ b/components/maidsite_desk_controller/example_basic.yaml @@ -1,6 +1,6 @@ esphome: - name: jiecang-desk-controller # change this! - friendly_name: Jiecang Desk Controller # change this! + name: maidsite-desk-controller # change this! + friendly_name: Maidsite Desk Controller # change this! on_boot: # don't touch if you don't know what you're doing! priority: 0 # when mostly everything else is done @@ -14,43 +14,47 @@ esphome: external_components: - source: type: git - url: https://github.com/Rocka84/esphome_components/ - components: [ jiecang_desk_controller ] + url: https://github.com/ElVit/esphome_maidsite_desk/ + components: [ maidsite_desk_controller ] uart: - id: uart_bus - tx_pin: TX - rx_pin: RX - baud_rate: 9600 + - id: uart_bus + tx_pin: $pin_tx + rx_pin: $pin_rx + baud_rate: 9600 -logger: - baud_rate: 0 # disable logging over uart, required when using the RX/TX pins for the controller - -# see full example for more options: https://github.com/Rocka84/esphome_components/blob/master/components/jiecang_desk_controller/example_full.yaml -jiecang_desk_controller: +# see full example for more options: https://github.com/Rocka84/esphome_components/blob/master/components/maidsite_desk_controller/example_full.yaml +maidsite_desk_controller: id: my_desk + + sensors: + height_abs: + name: "Height" + buttons: - move_up: - name: "Move up" - move_down: - name: "Move down" stop: name: "Stop" step_up: name: "Step up" step_down: name: "Step down" - position1: - name: "Position 1" - position2: - name: "Position 2" - position3: - name: "Position 3" - position4: - name: "Position 4" + goto_max: + name: "Move to MAX" + goto_min: + name: "Move to MIN" + goto_m1: + name: "Move to M1" + goto_m2: + name: "Move to M2" + goto_m3: + name: "Move to M3" + goto_m4: + name: "Move to M4" + numbers: - height: + height_abs: name: "Height" + mode: SLIDER # the usual stuff @@ -70,3 +74,4 @@ api: key: !secret encryption_key ota: +logger: diff --git a/components/jiecang_desk_controller/example_full.yaml b/components/maidsite_desk_controller/example_full.yaml similarity index 54% rename from components/jiecang_desk_controller/example_full.yaml rename to components/maidsite_desk_controller/example_full.yaml index 3647a94..7407eb7 100644 --- a/components/jiecang_desk_controller/example_full.yaml +++ b/components/maidsite_desk_controller/example_full.yaml @@ -1,9 +1,9 @@ esphome: - name: jiecang-desk-controller - friendly_name: Jiecang Desk Controller + name: maidsite-desk-controller + friendly_name: Maidsite Desk Controller on_boot: # This script is required to initialize the following sensors: - # height_pct, height_min, height_max, position1 - position4 + # height_pct, height_min, height_max, position_m1 - position_m4 # You can skip this if you don't use those. priority: 0 # when mostly everything else is done then: @@ -16,69 +16,79 @@ esphome: external_components: - source: type: local - path: rocka84_esphome_components/components/ + path: elvit_esphome_maidsite_desk/components/ # type: git - # url: https://github.com/Rocka84/esphome_components/ - components: [ jiecang_desk_controller ] + # url: https://github.com/ElVit/esphome_maidsite_desk/ + components: [ maidsite_desk_controller ] uart: - id: uart_bus - tx_pin: TX - rx_pin: RX - baud_rate: 9600 + - id: uart_bus + tx_pin: $pin_tx + rx_pin: $pin_rx + baud_rate: 9600 + # debug: + # direction: BOTH + # after: + # bytes: 9 + # sequence: + # - lambda: UARTDebug::log_hex(direction, bytes, ','); -logger: - baud_rate: 0 # disable logging over uart, required when using the RX/TX pins for the controller - -jiecang_desk_controller: +maidsite_desk_controller: id: my_desk + sensors: - height: - name: "Height" + height_abs: + name: "Height absolut" + height_pct: + name: "Height percent" height_min: name: "Height Min" height_max: name: "Height Max" - height_pct: - name: "Height Percent" - position1: - name: "Position 1" - position2: - name: "Position 2" - position3: - name: "Position 3" - position4: - name: "Position 4" + position_m1: + name: "Position M1" + position_m2: + name: "Position M2" + position_m3: + name: "Position M3" + position_m4: + name: "Position M4" + buttons: - move_up: - name: "Move up" - move_down: - name: "Move down" stop: name: "Stop" step_up: name: "Step up" step_down: name: "Step down" - position1: - name: "Position 1" - position2: - name: "Position 2" - position3: - name: "Position 3" - position4: - name: "Position 4" - save_position: - name: "Save Position" - move_up: - name: "Move up" - move_down: - name: "Move down" + goto_max: + name: "Move to MAX" + goto_min: + name: "Move to MIN" + goto_m1: + name: "Move to M1" + goto_m2: + name: "Move to M2" + goto_m3: + name: "Move to M3" + goto_m4: + name: "Move to M4" + save_m1: + name: "Save M1" + save_m2: + name: "Save M2" + save_m3: + name: "Save M3" + save_m4: + name: "Save M4" + numbers: - height: - name: "Height" + height_abs: + name: "Height absolut" + mode: SLIDER height_pct: - name: "Height Percent" + name: "Height percent" + mode: SLIDER ## lambda usage # button: @@ -97,17 +107,16 @@ jiecang_desk_controller: # - platform: template # name: "Position 2" # on_press: -# lambda: "id(my_desk).goto_position(2);" +# lambda: "id(my_desk).goto_mem_position(2);" # - platform: template # name: "Save Position 4" # on_press: -# lambda: "id(my_desk).save_position(4);" +# lambda: "id(my_desk).save_mem_position(4);" # - platform: template # name: "Go to 100cm" # on_press: # lambda: "id(my_desk).goto_height(100);" - # the usual stuff esp8266: @@ -126,3 +135,4 @@ api: key: !secret encryption_key ota: +logger: diff --git a/components/maidsite_desk_controller/maidsite_desk_controller.cpp b/components/maidsite_desk_controller/maidsite_desk_controller.cpp new file mode 100644 index 0000000..5c85b14 --- /dev/null +++ b/components/maidsite_desk_controller/maidsite_desk_controller.cpp @@ -0,0 +1,381 @@ +#include "maidsite_desk_controller.h" +#include "esphome/core/log.h" + +namespace esphome +{ + namespace maidsite_desk_controller + { + static const char *const TAG = "maidsite_desk_controller"; + + float MaidsiteDeskController::byte2float(int high, int low) + { + return static_cast((high << 8) + low) / 10; + } + + bool MaidsiteDeskController::bufferMessage(int data, unsigned int *buffer, int len) + { + // This is a very simple method of receiving messages from the desk. + // It will fail on messages that contain the value 0x7E in their payload. + // But it is super simple and works for the messages we care about. + + // Read message: + // format: 0xF2 0xF2 [command] [param_count] [[param] ...] [checksum] 0x7E + // checksum: sum of [command], [param_count] and all [param]s + + static int cmd_incoming = 0; // 0: wait for F2, 1: wait for 2nd F2, 2: buffer data + static int pos = 0; + + if (cmd_incoming < 2 && data == 0xF2) + { // start of message, must appear twice + cmd_incoming++; + pos = 0; + } + else if (cmd_incoming == 1) + { // no second F2 received + cmd_incoming = 0; + } + else if (cmd_incoming == 2) + { + if (data == 0x7E) + { // end of message + cmd_incoming = 0; + for (; pos < len - 1; pos++) + { // fill rest of buffer with zeros + buffer[pos] = 0; + } + return true; + } + else if (pos >= len) + { // message too long, drop it + cmd_incoming = 0; + } + else + { + buffer[pos++] = data; // buffer data + } + } // else: received garbage + + return false; + } + + void MaidsiteDeskController::handleMessage(unsigned int *message) + { + // ESP_LOGV("maidsite_desk_controller", "message %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", message[0], message[1], message[2], message[3], message[4], message[5], message[6], message[7], message[8], message[9]); + + switch (message[0]) + { + case 0x01: + ESP_LOGV("maidsite_desk_controller", "sensor_height 0x%0X%0X", message[2], message[3]); + float new_height; + new_height = byte2float(message[2], message[3]); + if (new_height == current_height) + return; + current_height = new_height; + if (sensor_height != nullptr) + sensor_height->publish_state(current_height); + if (number_height_abs != nullptr) + number_height_abs->publish_state(current_height); + + if (sensor_height_pct != nullptr && limit_max != 0) + sensor_height_pct->publish_state((current_height - limit_min) / (limit_max - limit_min) * 100); + if (number_height_pct != nullptr && limit_max != 0) + number_height_pct->publish_state(roundf((current_height - limit_min) / (limit_max - limit_min) * 1000) / 10); + break; + + case 0x20: + ESP_LOGV("maidsite_desk_controller", "sensor_limits 0x%0X max %i min %i", message[2], (message[2] & 1), (message[2] >> 4)); + + if ((message[2] & 1) == 0) + { // low nibble 0 -> no max limit, use physical_max + limit_max = physical_max; + if (sensor_height_max != nullptr) + sensor_height_max->publish_state(limit_max); + if (number_height_abs != nullptr) + number_height_abs->set_max_value(limit_max); + } + if ((message[2] >> 4) == 0) + { // high nibble 0 -> no min limit, use physical_min + limit_min = physical_min; + if (sensor_height_min != nullptr) + sensor_height_min->publish_state(limit_min); + if (number_height_abs != nullptr) + number_height_abs->set_min_value(limit_min); + } + break; + + case 0x07: + ESP_LOGV("maidsite_desk_controller", "sensor_physical_limits 0x%02X%02X 0x%02X%02X", message[2], message[3], message[4], message[5]); + physical_max = byte2float(message[2], message[3]); + physical_min = byte2float(message[4], message[5]); + break; + + case 0x21: + ESP_LOGV("maidsite_desk_controller", "sensor_height_max 0x%02X%02X", message[2], message[3]); + limit_max = byte2float(message[2], message[3]); + if (sensor_height_max != nullptr) + sensor_height_max->publish_state(limit_max); + if (number_height_abs != nullptr) + number_height_abs->set_max_value(limit_max); + break; + + case 0x22: + ESP_LOGV("maidsite_desk_controller", "sensor_height_min 0x%02X%02X", message[2], message[3]); + limit_min = byte2float(message[2], message[3]); + if (sensor_height_min != nullptr) + sensor_height_min->publish_state(limit_min); + if (number_height_abs != nullptr) + number_height_abs->set_min_value(limit_min); + break; + + case 0x25: + ESP_LOGV("maidsite_desk_controller", "sensor_position_m1 0x%02X%02X", message[2], message[3]); + if (sensor_position_m1 != nullptr) + sensor_position_m1->publish_state(byte2float(message[2], message[3])); + break; + + case 0x26: + ESP_LOGV("maidsite_desk_controller", "sensor_position_m2 0x%02X%02X", message[2], message[3]); + if (sensor_position_m2 != nullptr) + sensor_position_m2->publish_state(byte2float(message[2], message[3])); + break; + + case 0x27: + ESP_LOGV("maidsite_desk_controller", "sensor_position_m3 0x%02X%02X", message[2], message[3]); + if (sensor_position_m3 != nullptr) + sensor_position_m3->publish_state(byte2float(message[2], message[3])); + break; + + case 0x28: + ESP_LOGV("maidsite_desk_controller", "sensor_position_m4 0x%02X%02X", message[2], message[3]); + if (sensor_position_m4 != nullptr) + sensor_position_m4->publish_state(byte2float(message[2], message[3])); + break; + + // case 0x0E: + // ESP_LOGV("maidsite_desk_controller", "units 0x%02X", message[2]); + // if (units != nullptr) + // units->publish_state(byte2float(message[2], message[3])); + // break; + + default: + ESP_LOGV("maidsite_desk_controller", "unknown message %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", message[0], message[1], message[2], message[3], message[4], message[5], message[6], message[7], message[8], message[9]); + } + } + + void MaidsiteDeskController::update() + { + const int max_length = 10; + static unsigned int buffer[max_length]; + while (available()) + { + if (bufferMessage(read(), buffer, max_length)) + { + handleMessage(buffer); + } + } + } + + void MaidsiteDeskController::add_button(button::Button *btn, int action) + { + btn->add_on_press_callback([this, action]() { this->button_press_action(action); }); + } + + // Write message: + // format: 0xF1 0xF1 [command] [param_count] [[param] ...] [checksum] 0x7E + // checksum: sum of [command], [param_count] and all [param]s + void MaidsiteDeskController::send_simple_command(unsigned char cmd) + { + write_array({0xF1, 0xF1, cmd, 0x00, cmd, 0x7E}); + } + + void MaidsiteDeskController::send_2byte_command(unsigned char cmd, unsigned char high_byte, unsigned char low_byte) + { + unsigned char checksum = cmd + 2 + high_byte + low_byte; + write_array({ 0xF1, 0xF1, cmd, 0x02, high_byte, low_byte, checksum, 0x7E }); + } + + void MaidsiteDeskController::step_up() + { + send_simple_command(0x01); + } + + void MaidsiteDeskController::step_down() + { + send_simple_command(0x02); + } + + void MaidsiteDeskController::stop() + { + send_simple_command(0x2B); + } + + void MaidsiteDeskController::goto_mem_position(int pos) + { + switch (pos) + { + case 1: + send_simple_command(0x05); + break; + case 2: + send_simple_command(0x06); + break; + case 3: + send_simple_command(0x27); + break; + case 4: + send_simple_command(0x28); + break; + } + } + + void MaidsiteDeskController::save_mem_position(int pos) + { + switch (pos) + { + case 1: + send_simple_command(0x03); + break; + case 2: + send_simple_command(0x04); + break; + case 3: + send_simple_command(0x25); + break; + case 4: + send_simple_command(0x26); + break; + } + } + + void MaidsiteDeskController::request_physical_limits() + { + send_simple_command(0x0C); + } + + void MaidsiteDeskController::request_limits() + { + send_simple_command(0x20); + } + + void MaidsiteDeskController::request_settings() + { + send_simple_command(0x07); + } + + void MaidsiteDeskController::request_move_to() + { + send_simple_command(0x1B); + } + + void MaidsiteDeskController::goto_height(float height) + { + unsigned char high_byte = ((int)height * 10) >> 8; + unsigned char low_byte = ((int)height * 10) & 0xFF; + + send_2byte_command(0x80, high_byte, low_byte); + request_move_to(); + } + + void MaidsiteDeskController::goto_max_position() + { + goto_height(limit_max); + } + + void MaidsiteDeskController::goto_min_position() + { + goto_height(limit_min); + } + + void MaidsiteDeskController::button_press_action(int action) + { + ESP_LOGV("MaidsiteDeskController", "button_press_action %i", action); + switch (action) + { + case BUTTON_STEP_UP: + step_up(); + break; + case BUTTON_STEP_DOWN: + step_down(); + break; + case BUTTON_STOP: + stop(); + break; + case BUTTON_GOTO_MAX: + goto_max_position(); + break; + case BUTTON_GOTO_MIN: + goto_min_position(); + break; + case BUTTON_GOTO_M1: + goto_mem_position(1); + break; + case BUTTON_GOTO_M2: + goto_mem_position(2); + break; + case BUTTON_GOTO_M3: + goto_mem_position(3); + break; + case BUTTON_GOTO_M4: + goto_mem_position(4); + break; + case BUTTON_SAVE_M1: + save_mem_position(1); + delay(100); + request_settings(); + break; + case BUTTON_SAVE_M2: + save_mem_position(2); + delay(100); + request_settings(); + break; + case BUTTON_SAVE_M3: + save_mem_position(3); + delay(100); + request_settings(); + break; + case BUTTON_SAVE_M4: + save_mem_position(4); + delay(100); + request_settings(); + break; + } + } + + void MaidsiteDeskController::add_number(MaidsiteDeskNumber *number, int type) + { + switch (type) + { + case NUMBER_HEIGHT: + number_height_abs = number; + break; + case NUMBER_HEIGHT_PCT: + number_height_pct = number; + number_height_pct->set_min_value(0); + number_height_pct->set_max_value(100); + break; + default: + return; + } + number->set_type(type); + number->set_parent(this); + } + + void MaidsiteDeskController::number_control(int type, float value) + { + ESP_LOGV("MaidsiteDeskController", "number_control %i", type); + switch (type) + { + case NUMBER_HEIGHT: + goto_height(value); + break; + case NUMBER_HEIGHT_PCT: + if (limit_max > 0 && limit_max > limit_min) + goto_height((limit_max - limit_min) * value / 100 + limit_min); + break; + } + } + + void MaidsiteDeskButton::press_action() {} + + } // namespace maidsite_desk_controller +} // namespace esphome diff --git a/components/maidsite_desk_controller/maidsite_desk_controller.h b/components/maidsite_desk_controller/maidsite_desk_controller.h new file mode 100644 index 0000000..237b129 --- /dev/null +++ b/components/maidsite_desk_controller/maidsite_desk_controller.h @@ -0,0 +1,105 @@ +#pragma once + +#include +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/button/button.h" +#include "esphome/components/uart/uart.h" +#include "esphome/core/hal.h" +#include "esphome/core/log.h" +#include "maidsite_desk_number.h" + +#define BUTTON_STEP_UP 0 +#define BUTTON_STEP_DOWN 1 +#define BUTTON_STOP 2 +#define BUTTON_GOTO_MAX 3 +#define BUTTON_GOTO_MIN 4 +#define BUTTON_GOTO_M1 5 +#define BUTTON_GOTO_M2 6 +#define BUTTON_GOTO_M3 7 +#define BUTTON_GOTO_M4 8 +#define BUTTON_SAVE_M1 9 +#define BUTTON_SAVE_M2 10 +#define BUTTON_SAVE_M3 11 +#define BUTTON_SAVE_M4 12 + +#define NUMBER_HEIGHT 0 +#define NUMBER_HEIGHT_PCT 1 + +namespace esphome +{ + namespace maidsite_desk_controller + { + + class MaidsiteDeskController : public PollingComponent, public sensor::Sensor, public uart::UARTDevice + { + private: + float current_height = 0; + float limit_min = 0; + float limit_max = 0; + float physical_min = 0; + float physical_max = 0; + + float byte2float(int high, int low); + bool bufferMessage(int data, unsigned int *buffer, int len); + void handleMessage(unsigned int *message); + + public: + void update() override; + + void set_sensor_height(sensor::Sensor *sensor) { this->sensor_height = sensor; } + void set_sensor_height_min(sensor::Sensor *sensor) { this->sensor_height_min = sensor; } + void set_sensor_height_max(sensor::Sensor *sensor) { this->sensor_height_max = sensor; } + void set_sensor_height_pct(sensor::Sensor *sensor) { this->sensor_height_pct = sensor; } + void set_sensor_position_m1(sensor::Sensor *sensor) { this->sensor_position_m1 = sensor; } + void set_sensor_position_m2(sensor::Sensor *sensor) { this->sensor_position_m2 = sensor; } + void set_sensor_position_m3(sensor::Sensor *sensor) { this->sensor_position_m3 = sensor; } + void set_sensor_position_m4(sensor::Sensor *sensor) { this->sensor_position_m4 = sensor; } + + void add_button(button::Button *btn, int action); + void add_number(MaidsiteDeskNumber *number, int type); + + void send_simple_command(unsigned char cmd); + void send_2byte_command(unsigned char cmd, unsigned char high_byte, unsigned char low_byte); + + void step_up(); + void step_down(); + void stop(); + void goto_mem_position(int pos); + void save_mem_position(int pos); + void goto_height(float height); + void goto_max_position(); + void goto_min_position(); + + void request_physical_limits(); + void request_limits(); + void request_settings(); + void request_move_to(); + + void number_control(int type, float value); + + protected: + Sensor *sensor_height{nullptr}; + Sensor *sensor_height_min{nullptr}; + Sensor *sensor_height_max{nullptr}; + Sensor *sensor_height_pct{nullptr}; + + Sensor *sensor_position_m1{nullptr}; + Sensor *sensor_position_m2{nullptr}; + Sensor *sensor_position_m3{nullptr}; + Sensor *sensor_position_m4{nullptr}; + + MaidsiteDeskNumber *number_height_abs{nullptr}; + MaidsiteDeskNumber *number_height_pct{nullptr}; + + void button_press_action(int type); + }; + + class MaidsiteDeskButton : public Component, public button::Button + { + protected: + void press_action() override; + }; + + } // namespace maidsite_desk_controller +} // namespace esphome diff --git a/components/maidsite_desk_controller/maidsite_desk_number.cpp b/components/maidsite_desk_controller/maidsite_desk_number.cpp new file mode 100644 index 0000000..00a3b49 --- /dev/null +++ b/components/maidsite_desk_controller/maidsite_desk_number.cpp @@ -0,0 +1,37 @@ +#include "maidsite_desk_number.h" +#include "maidsite_desk_controller.h" +#include "esphome/core/log.h" + +namespace esphome +{ + namespace maidsite_desk_controller + { + + static const char *const TAG = "maidsite_desk.number"; + + void MaidsiteDeskNumber::setup() {} + + void MaidsiteDeskNumber::dump_config() + { + LOG_NUMBER("", "MaidsiteDeskNumber", this); + ESP_LOGCONFIG(TAG, " type %i", type); + } + + void MaidsiteDeskNumber::control(float value) + { + this->publish_state(value); + parent->number_control(this->type, value); + } + + void MaidsiteDeskNumber::set_min_value(float value) + { + traits.set_min_value(value); + } + + void MaidsiteDeskNumber::set_max_value(float value) + { + traits.set_max_value(value); + } + + } // namespace maidsite_desk_controller +} // namespace esphome diff --git a/components/maidsite_desk_controller/maidsite_desk_number.h b/components/maidsite_desk_controller/maidsite_desk_number.h new file mode 100644 index 0000000..c537f3d --- /dev/null +++ b/components/maidsite_desk_controller/maidsite_desk_number.h @@ -0,0 +1,35 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/number/number.h" +#include "esphome/core/log.h" + +namespace esphome +{ + namespace maidsite_desk_controller + { + + class MaidsiteDeskController; + + class MaidsiteDeskNumber : public number::Number, public Component + { + private: + int type; + MaidsiteDeskController *parent; + + public: + void setup() override; + void dump_config() override; + + void set_parent(MaidsiteDeskController *parent) { this->parent = parent; } + void set_type(int type) { this->type = type; } + + void set_min_value(float value); + void set_max_value(float value); + + protected: + void control(float value) override; + }; + + } // namespace maidsite_desk_controller +} // namespace esphome diff --git a/components/jiecang_desk_controller/stl/D1mini Case Bottom.stl b/components/maidsite_desk_controller/stl/D1mini Case Bottom.stl similarity index 100% rename from components/jiecang_desk_controller/stl/D1mini Case Bottom.stl rename to components/maidsite_desk_controller/stl/D1mini Case Bottom.stl diff --git a/components/jiecang_desk_controller/stl/D1mini Case Clamp.stl b/components/maidsite_desk_controller/stl/D1mini Case Clamp.stl similarity index 100% rename from components/jiecang_desk_controller/stl/D1mini Case Clamp.stl rename to components/maidsite_desk_controller/stl/D1mini Case Clamp.stl diff --git a/components/jiecang_desk_controller/stl/D1mini Case Table Clamp A.stl b/components/maidsite_desk_controller/stl/D1mini Case Table Clamp A.stl similarity index 100% rename from components/jiecang_desk_controller/stl/D1mini Case Table Clamp A.stl rename to components/maidsite_desk_controller/stl/D1mini Case Table Clamp A.stl diff --git a/components/jiecang_desk_controller/stl/D1mini Case Table Clamp B.stl b/components/maidsite_desk_controller/stl/D1mini Case Table Clamp B.stl similarity index 100% rename from components/jiecang_desk_controller/stl/D1mini Case Table Clamp B.stl rename to components/maidsite_desk_controller/stl/D1mini Case Table Clamp B.stl diff --git a/components/jiecang_desk_controller/stl/D1mini Case Top.stl b/components/maidsite_desk_controller/stl/D1mini Case Top.stl similarity index 100% rename from components/jiecang_desk_controller/stl/D1mini Case Top.stl rename to components/maidsite_desk_controller/stl/D1mini Case Top.stl diff --git a/example_jiecang_desk_controller.yaml b/example_jiecang_desk_controller.yaml deleted file mode 120000 index fa6cf37..0000000 --- a/example_jiecang_desk_controller.yaml +++ /dev/null @@ -1 +0,0 @@ -components/jiecang_desk_controller/example_basic.yaml \ No newline at end of file diff --git a/example_maidsite_desk_controller.yaml b/example_maidsite_desk_controller.yaml new file mode 100644 index 0000000..ee82bf4 --- /dev/null +++ b/example_maidsite_desk_controller.yaml @@ -0,0 +1 @@ +components/maidsite_desk_controller/example_basic.yaml \ No newline at end of file