Refactored Maidsite Desk Component

This commit is contained in:
ElVit
2025-01-30 11:23:49 +01:00
parent 07e4f2cd8e
commit 2610b393fa
23 changed files with 884 additions and 742 deletions
+29
View File
@@ -0,0 +1,29 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import uart
from esphome.const import CONF_ID
CODEOWNERS = ['@elvit']
MULTICONF = True
DEPENDENCIES = ['uart']
CONF_MAIDSITE_DESK_ID = "maidsite_desk"
maidsite_desk_ns = cg.esphome_ns.namespace('maidsite_desk')
MaidsiteDeskComponent = maidsite_desk_ns.class_('MaidsiteDeskComponent', cg.Component, uart.UARTDevice)
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(MaidsiteDeskComponent),
}
)
.extend(uart.UART_DEVICE_SCHEMA)
.extend(cv.COMPONENT_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)
+101
View File
@@ -0,0 +1,101 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import button
from esphome.const import (
ENTITY_CATEGORY_CONFIG,
)
from .. import CONF_MAIDSITE_DESK_ID, MaidsiteDeskComponent, maidsite_desk_ns
CONF_STEP_UP = "step_up"
CONF_STEP_DOWN = "step_down"
CONF_STOP = "stop"
CONF_GOTO_MAX = "goto_max"
CONF_GOTO_MIN = "goto_min"
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"
TYPES = [
CONF_STEP_UP,
CONF_STEP_DOWN,
CONF_STOP,
CONF_GOTO_MAX,
CONF_GOTO_MIN,
CONF_GOTO_M1,
CONF_GOTO_M2,
CONF_GOTO_M3,
CONF_GOTO_M4,
CONF_SAVE_M1,
CONF_SAVE_M2,
CONF_SAVE_M3,
CONF_SAVE_M4,
]
MaidsiteDeskButton = maidsite_desk_ns.class_("MaidsiteDeskButton", button.Button)
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(CONF_MAIDSITE_DESK_ID): cv.use_id(MaidsiteDeskComponent),
cv.Optional(CONF_STEP_UP): button.button_schema(
MaidsiteDeskButton,
),
cv.Optional(CONF_STEP_DOWN): button.button_schema(
MaidsiteDeskButton,
),
cv.Optional(CONF_STOP): button.button_schema(
MaidsiteDeskButton,
),
cv.Optional(CONF_GOTO_MAX): button.button_schema(
MaidsiteDeskButton,
),
cv.Optional(CONF_GOTO_MIN): button.button_schema(
MaidsiteDeskButton,
),
cv.Optional(CONF_GOTO_M1): button.button_schema(
MaidsiteDeskButton,
),
cv.Optional(CONF_GOTO_M2): button.button_schema(
MaidsiteDeskButton,
),
cv.Optional(CONF_GOTO_M3): button.button_schema(
MaidsiteDeskButton,
),
cv.Optional(CONF_GOTO_M4): button.button_schema(
MaidsiteDeskButton,
),
cv.Optional(CONF_SAVE_M1): button.button_schema(
MaidsiteDeskButton,
entity_category=ENTITY_CATEGORY_CONFIG,
),
cv.Optional(CONF_SAVE_M2): button.button_schema(
MaidsiteDeskButton,
entity_category=ENTITY_CATEGORY_CONFIG,
),
cv.Optional(CONF_SAVE_M3): button.button_schema(
MaidsiteDeskButton,
entity_category=ENTITY_CATEGORY_CONFIG,
),
cv.Optional(CONF_SAVE_M4): button.button_schema(
MaidsiteDeskButton,
entity_category=ENTITY_CATEGORY_CONFIG,
),
}
)
async def to_code(config):
hub = await cg.get_variable(config[CONF_MAIDSITE_DESK_ID])
for key in TYPES:
await setup_conf(config, key, hub)
async def setup_conf(parent_config, key, hub):
if child_config := parent_config.get(key):
var = await button.new_button(child_config)
await cg.register_parented(var, parent_config[CONF_MAIDSITE_DESK_ID])
cg.add(getattr(hub, f"set_{key}_button")(var))
@@ -0,0 +1,13 @@
#include "maidsite_desk_button.h"
namespace esphome
{
namespace maidsite_desk
{
void MaidsiteDeskButton::press_action()
{
this->parent_->button_press_action(this);
}
} // namespace maidsite_desk
} // namespace esphome
@@ -0,0 +1,19 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../maidsite_desk.h"
namespace esphome
{
namespace maidsite_desk
{
class MaidsiteDeskButton : public button::Button, public Parented<MaidsiteDeskComponent>
{
public:
MaidsiteDeskButton() = default;
protected:
void press_action() override;
};
} // namespace maidsite_desk
} // namespace esphome
+459
View File
@@ -0,0 +1,459 @@
#include "maidsite_desk.h"
#define BUTTON_UNIT "unit"
#define BUTTON_STEP_UP "step_up"
#define BUTTON_STEP_DOWN "step_down"
#define BUTTON_STOP "stop"
#define BUTTON_GOTO_MAX "goto_max"
#define BUTTON_GOTO_MIN "goto_min"
#define BUTTON_GOTO_M1 "goto_m1"
#define BUTTON_GOTO_M2 "goto_m2"
#define BUTTON_GOTO_M3 "goto_m3"
#define BUTTON_GOTO_M4 "goto_m4"
#define BUTTON_SAVE_M1 "save_m1"
#define BUTTON_SAVE_M2 "save_m2"
#define BUTTON_SAVE_M3 "save_m3"
#define BUTTON_SAVE_M4 "save_m4"
#define NUMBER_HEIGHT_ABS "height_abs"
#define NUMBER_HEIGHT_PCT "height_pct"
namespace esphome
{
namespace maidsite_desk
{
static const char *const TAG = "maidsite_desk";
void MaidsiteDeskComponent::dump_config()
{
ESP_LOGCONFIG(TAG, "Maidsite Desk");
#ifdef USE_SENSOR
LOG_SENSOR("", "Maidsite Desk Sensor", this->unit_sensor_);
LOG_SENSOR("", "Maidsite Desk Sensor", this->height_abs_sensor_);
LOG_SENSOR("", "Maidsite Desk Sensor", this->height_pct_sensor_);
LOG_SENSOR("", "Maidsite Desk Sensor", this->height_min_sensor_);
LOG_SENSOR("", "Maidsite Desk Sensor", this->height_max_sensor_);
LOG_SENSOR("", "Maidsite Desk Sensor", this->position_m1_sensor_);
LOG_SENSOR("", "Maidsite Desk Sensor", this->position_m2_sensor_);
LOG_SENSOR("", "Maidsite Desk Sensor", this->position_m3_sensor_);
LOG_SENSOR("", "Maidsite Desk Sensor", this->position_m4_sensor_);
#endif
#ifdef USE_BUTTON
LOG_BUTTON("", "Maidsite Desk Button", this->unit_button_);
LOG_BUTTON("", "Maidsite Desk Button", this->step_up_button_);
LOG_BUTTON("", "Maidsite Desk Button", this->step_down_button_);
LOG_BUTTON("", "Maidsite Desk Button", this->stop_button_);
LOG_BUTTON("", "Maidsite Desk Button", this->goto_max_button_);
LOG_BUTTON("", "Maidsite Desk Button", this->goto_min_button_);
LOG_BUTTON("", "Maidsite Desk Button", this->goto_m1_button_);
LOG_BUTTON("", "Maidsite Desk Button", this->goto_m2_button_);
LOG_BUTTON("", "Maidsite Desk Button", this->goto_m3_button_);
LOG_BUTTON("", "Maidsite Desk Button", this->goto_m4_button_);
LOG_BUTTON("", "Maidsite Desk Button", this->save_m1_button_);
LOG_BUTTON("", "Maidsite Desk Button", this->save_m2_button_);
LOG_BUTTON("", "Maidsite Desk Button", this->save_m3_button_);
LOG_BUTTON("", "Maidsite Desk Button", this->save_m4_button_);
LOG_BUTTON("", "Maidsite Desk Button", this->save_m4_button_);
#endif
#ifdef USE_NUMBER
LOG_NUMBER("", "Maidsite Desk Number", this->height_abs_number_);
LOG_NUMBER("", "Maidsite Desk Number", this->height_pct_number_);
#endif
}
void MaidsiteDeskComponent::setup()
{
ESP_LOGCONFIG(TAG, "Setting up maidsite Desk ...");
delay(10);
height_abs_number_->traits.set_min_value(0);
height_abs_number_->traits.set_max_value(120);
height_abs_number_->traits.set_step(.2);
height_pct_number_->traits.set_min_value(0);
height_pct_number_->traits.set_max_value(120);
height_pct_number_->traits.set_step(.1);
request_physical_limits();
request_limits();
request_settings();
}
void MaidsiteDeskComponent::loop()
{
// 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
uint8_t oneByte;
while (this->available())
{
this->read_byte(&oneByte);
// Message shall start with 0xF2, if not skip this byte
if (!this->response_receiving_)
{
if (oneByte != 0xF2)
continue;
this->response_receiving_ = true;
}
// Add current byte to message buffer
this->response_message_.push_back(oneByte);
// Discard message if 2. byte is not 0xF2
if (this->response_message_.size() == 2 && oneByte != 0xF2)
{
ESP_LOGW(TAG, "Invalid response message: 2. byte is 0x%02X but expexted is 0xF2", oneByte);
delay(10);
this->response_message_.clear();
this->response_receiving_ = false;
continue;
}
// Discard message if it is too long
if (this->response_message_.size() > 10)
{
ESP_LOGW(TAG, "Response message too long: expected not more than 10 bytes");
delay(10);
this->response_message_.clear();
this->response_receiving_ = false;
continue;
}
// Decode message if message is complete (last byte shall be 0x7E)
if (oneByte == 0x7E)
{
this->log_uart_hex("<<<", this->response_message_, ',');
this->decode_response(this->response_message_);
this->response_message_.clear();
this->response_receiving_ = false;
}
}
}
void MaidsiteDeskComponent::log_uart_hex(std::string prefix, std::vector<uint8_t> bytes, uint8_t separator)
{
std::string logStr;
logStr = "[" + std::to_string(bytes.size()) + "]";
ESP_LOGD(TAG, "%s %s", prefix.c_str(), logStr.c_str());
delay(10);
logStr = "";
char buffer[5];
for (size_t i = 0; i < bytes.size(); i++)
{
if (i > 0) logStr += separator;
sprintf(buffer, "%02X", bytes[i]);
logStr += buffer;
}
size_t chunkSize = 90;
for (size_t i = 0; i < logStr.length(); i += chunkSize)
{
ESP_LOGD(TAG, "%s %s", prefix.c_str(), logStr.substr(i, chunkSize).c_str());
delay(10);
}
}
void MaidsiteDeskComponent::decode_response(std::vector<uint8_t> message)
{
// ToDo: Add checksum check
switch (message[2])
{
case 0x01:
ESP_LOGD(TAG, "set height 0x%0X%0X", message[4], message[5]);
delay(10);
float new_height;
new_height = byte2float(message[4], message[5]);
if (new_height == this->current_height_)
return;
this->current_height_ = new_height;
if (this->height_abs_sensor_ != nullptr)
this->height_abs_sensor_->publish_state(this->current_height_);
if (this->height_abs_number_ != nullptr)
this->height_abs_number_->publish_state(this->current_height_);
if (this->height_pct_sensor_ != nullptr && limit_max_ != 0)
this->height_pct_sensor_->publish_state((this->current_height_ - this->limit_min_) / (this->limit_max_ - this->limit_min_) * 100);
if (this->height_pct_number_ != nullptr && limit_max_ != 0)
this->height_pct_number_->publish_state(roundf((this->current_height_ - this->limit_min_) / (this->limit_max_ - this->limit_min_) * 1000) / 10);
break;
case 0x20:
ESP_LOGD(TAG, "set limits 0x%0X max %i min %i", message[4], (message[5] & 1), (message[4] >> 4));
delay(10);
if ((message[4] & 1) == 0)
{ // low nibble 0 -> no max limit, use physical_max_
this->limit_max_ = this->physical_max_;
if (this->height_max_sensor_ != nullptr)
this->height_max_sensor_->publish_state(this->limit_max_);
if (height_abs_number_ != nullptr)
this->height_abs_number_->traits.set_max_value(this->limit_max_);
}
if ((message[4] >> 4) == 0)
{ // high nibble 0 -> no min limit, use physical_min_
this->limit_min_ = this->physical_min_;
if (this->height_min_sensor_ != nullptr)
this->height_min_sensor_->publish_state(limit_min_);
if (height_abs_number_ != nullptr)
this->height_abs_number_->traits.set_min_value(limit_min_);
}
break;
case 0x07:
ESP_LOGD(TAG, "set physical limits 0x%02X%02X 0x%02X%02X", message[4], message[5], message[6], message[7]);
delay(10);
this->physical_max_ = this->byte2float(message[4], message[5]);
this->physical_min_ = this->byte2float(message[6], message[7]);
break;
case 0x21:
ESP_LOGD(TAG, "set height max 0x%02X%02X", message[4], message[5]);
delay(10);
this->limit_max_ = this->byte2float(message[4], message[5]);
if (this->height_max_sensor_ != nullptr)
this->height_max_sensor_->publish_state(limit_max_);
if (height_abs_number_ != nullptr)
this->height_abs_number_->traits.set_max_value(limit_max_);
break;
case 0x22:
ESP_LOGD(TAG, "set height min 0x%02X%02X", message[4], message[5]);
delay(10);
this->limit_min_ = this->byte2float(message[4], message[5]);
if (this->height_min_sensor_ != nullptr)
this->height_min_sensor_->publish_state(limit_min_);
if (height_abs_number_ != nullptr)
this->height_abs_number_->traits.set_min_value(limit_min_);
break;
case 0x25:
ESP_LOGD(TAG, "set position m1 0x%02X%02X", message[4], message[5]);
delay(10);
if (this->position_m1_sensor_ != nullptr)
this->position_m1_sensor_->publish_state(this->byte2float(message[4], message[5]));
break;
case 0x26:
ESP_LOGD(TAG, "set position m2 0x%02X%02X", message[4], message[5]);
delay(10);
if (this->position_m2_sensor_ != nullptr)
this->position_m2_sensor_->publish_state(this->byte2float(message[4], message[5]));
break;
case 0x27:
ESP_LOGD(TAG, "set position m3 0x%02X%02X", message[4], message[5]);
delay(10);
if (this->position_m3_sensor_ != nullptr)
this->position_m3_sensor_->publish_state(this->byte2float(message[4], message[5]));
break;
case 0x28:
ESP_LOGD(TAG, "set position m4 0x%02X%02X", message[4], message[5]);
delay(10);
if (this->position_m4_sensor_ != nullptr)
this->position_m4_sensor_->publish_state(this->byte2float(message[4], message[5]));
break;
// case 0x0E:
// ESP_LOGD(TAG, "units 0x%02X", message[4]);
// if (units != nullptr)
// units->publish_state(byte2float(message[4], message[5]));
// break;
default:
ESP_LOGD(TAG, "Received unknown message");
delay(10);
}
}
float MaidsiteDeskComponent::byte2float(int high, int low)
{
return static_cast<float>((high << 8) + low) / 10;
}
// Write message:
// format: 0xF1 0xF1 [command] [param_count] [[param] ...] [checksum] 0x7E
// checksum: sum of [command], [param_count] and all [param]s
void MaidsiteDeskComponent::send_simple_command(unsigned char cmd)
{
this->request_message_.clear();
this->request_message_.insert(this->request_message_.end(), { 0xF1, 0xF1, cmd, 0x00, cmd, 0x7E });
this->write_array(this->request_message_);
this->log_uart_hex(">>>", this->request_message_, ',');
delay(100); // NOLINT
}
void MaidsiteDeskComponent::send_2byte_command(unsigned char cmd, unsigned char high_byte, unsigned char low_byte)
{
unsigned char checksum = cmd + 2 + high_byte + low_byte;
this->request_message_.clear();
this->request_message_.insert(this->request_message_.end(), { 0xF1, 0xF1, cmd, 0x02, high_byte, low_byte, checksum, 0x7E });
this->write_array(this->request_message_);
this->log_uart_hex(">>>", this->request_message_, ',');
delay(100); // NOLINT
}
void MaidsiteDeskComponent::step_up()
{
this->send_simple_command(0x01);
}
void MaidsiteDeskComponent::step_down()
{
this->send_simple_command(0x02);
}
void MaidsiteDeskComponent::stop()
{
this->send_simple_command(0x2B);
}
void MaidsiteDeskComponent::goto_mem_position(int pos)
{
switch (pos)
{
case 1:
this->send_simple_command(0x05);
break;
case 2:
this->send_simple_command(0x06);
break;
case 3:
this->send_simple_command(0x27);
break;
case 4:
this->send_simple_command(0x28);
break;
}
}
void MaidsiteDeskComponent::save_mem_position(int pos)
{
switch (pos)
{
case 1:
this->send_simple_command(0x03);
break;
case 2:
this->send_simple_command(0x04);
break;
case 3:
this->send_simple_command(0x25);
break;
case 4:
this->send_simple_command(0x26);
break;
}
}
void MaidsiteDeskComponent::request_physical_limits()
{
this->send_simple_command(0x0C);
}
void MaidsiteDeskComponent::request_limits()
{
this->send_simple_command(0x20);
}
void MaidsiteDeskComponent::request_settings()
{
this->send_simple_command(0x07);
}
void MaidsiteDeskComponent::request_move_to()
{
this->send_simple_command(0x1B);
}
void MaidsiteDeskComponent::goto_max_position()
{
this->goto_height(limit_max_);
}
void MaidsiteDeskComponent::goto_min_position()
{
this->goto_height(limit_min_);
}
void MaidsiteDeskComponent::goto_height(float height)
{
unsigned char high_byte = ((int)height * 10) >> 8;
unsigned char low_byte = ((int)height * 10) & 0xFF;
this->send_2byte_command(0x80, high_byte, low_byte);
this->request_move_to();
}
void MaidsiteDeskComponent::button_press_action(button::Button* object)
{
ESP_LOGD(TAG, "button %s pressed", object->get_name());
delay(10);
if (object == step_up_button_)
this->step_up();
else if (object == step_down_button_)
this->step_down();
else if (object == stop_button_)
this->stop();
else if (object == goto_max_button_)
this->goto_max_position();
else if (object == goto_min_button_)
this->goto_min_position();
else if (object == goto_m1_button_)
this->goto_mem_position(1);
else if (object == goto_m2_button_)
this->goto_mem_position(2);
else if (object == goto_m3_button_)
this->goto_mem_position(3);
else if (object == goto_m4_button_)
this->goto_mem_position(4);
else if (object == save_m1_button_)
{
this->save_mem_position(1);
this->request_settings();
}
else if (object == save_m2_button_)
{
this->save_mem_position(2);
this->request_settings();
}
else if (object == save_m3_button_)
{
this->save_mem_position(3);
this->request_settings();
}
else if (object == save_m4_button_)
{
this->save_mem_position(4);
this->request_settings();
}
}
void MaidsiteDeskComponent::number_control(number::Number* object, float value)
{
ESP_LOGD(TAG, "number %s controlled", object->get_name());
delay(10);
if (object == height_abs_number_)
this->goto_height(value);
else if (object == height_pct_number_)
if (limit_max_ > 0 && limit_max_ > limit_min_)
this->goto_height((limit_max_ - limit_min_) * value / 100 + limit_min_);
}
} // namespace maidsite_desk
} // namespace esphome
+103
View File
@@ -0,0 +1,103 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/defines.h"
#include "esphome/core/log.h"
#include "esphome/components/uart/uart.h"
#ifdef USE_SENSOR
#include "esphome/components/sensor/sensor.h"
#endif
#ifdef USE_BUTTON
#include "esphome/components/button/button.h"
#endif
#ifdef USE_NUMBER
#include "esphome/components/number/number.h"
#endif
#include <vector>
#include <string>
namespace esphome
{
namespace maidsite_desk
{
class MaidsiteDeskComponent : public Component, public uart::UARTDevice
{
public:
#ifdef USE_SENSOR
SUB_SENSOR(unit);
SUB_SENSOR(height_abs);
SUB_SENSOR(height_pct);
SUB_SENSOR(height_min);
SUB_SENSOR(height_max);
SUB_SENSOR(position_m1);
SUB_SENSOR(position_m2);
SUB_SENSOR(position_m3);
SUB_SENSOR(position_m4);
#endif
#ifdef USE_BUTTON
SUB_BUTTON(unit);
SUB_BUTTON(step_up);
SUB_BUTTON(step_down);
SUB_BUTTON(stop);
SUB_BUTTON(goto_max);
SUB_BUTTON(goto_min);
SUB_BUTTON(goto_m1);
SUB_BUTTON(goto_m2);
SUB_BUTTON(goto_m3);
SUB_BUTTON(goto_m4);
SUB_BUTTON(save_m1);
SUB_BUTTON(save_m2);
SUB_BUTTON(save_m3);
SUB_BUTTON(save_m4);
#endif
#ifdef USE_NUMBER
SUB_NUMBER(height_abs);
SUB_NUMBER(height_pct);
#endif
MaidsiteDeskComponent() = default;
float get_setup_priority() const override { return setup_priority::LATE; }
void dump_config() override;
void setup() override;
void loop() override;
void button_press_action(button::Button* object);
void number_control(number::Number* object, float value);
void request_physical_limits();
void request_limits();
void request_settings();
void request_move_to();
protected:
void decode_response(std::vector<uint8_t> message);
void send_simple_command(unsigned char cmd);
void send_2byte_command(unsigned char cmd, unsigned char high_byte, unsigned char low_byte);
float byte2float(int high, int low);
void log_uart_hex(std::string prefix, std::vector<uint8_t> bytes, uint8_t separator);
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();
private:
std::vector<uint8_t> response_message_;
std::vector<uint8_t> request_message_;
uint8_t response_payload_length_;
uint8_t request_payload_length_;
bool response_receiving_{false};
bool request_receiving_{false};
float current_height_ = 0;
float limit_min_ = 0;
float limit_max_ = 0;
float physical_min_ = 0;
float physical_max_ = 0;
};
} // namespace maidsite_desk
} // namespace esphome
@@ -0,0 +1,45 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import number
from esphome.const import (
UNIT_CENTIMETER,
UNIT_PERCENT,
)
from .. import CONF_MAIDSITE_DESK_ID, MaidsiteDeskComponent, maidsite_desk_ns
CONF_HEIGHT_ABS = "height_abs"
CONF_HEIGHT_PCT = "height_pct"
TYPES = [
CONF_HEIGHT_ABS,
CONF_HEIGHT_PCT,
]
MaidsiteDeskNumber = maidsite_desk_ns.class_("MaidsiteDeskNumber", number.Number)
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(CONF_MAIDSITE_DESK_ID): cv.use_id(MaidsiteDeskComponent),
cv.Optional(CONF_HEIGHT_ABS): number.number_schema(
MaidsiteDeskNumber,
unit_of_measurement=UNIT_CENTIMETER,
),
cv.Optional(CONF_HEIGHT_PCT): number.number_schema(
MaidsiteDeskNumber,
unit_of_measurement=UNIT_PERCENT,
),
}
)
async def to_code(config):
hub = await cg.get_variable(config[CONF_MAIDSITE_DESK_ID])
for key in TYPES:
await setup_conf(config, key, hub)
async def setup_conf(parent_config, key, hub):
if child_config := parent_config.get(key):
var = await number.new_number(child_config, min_value=0, max_value=100, step=.1)
await cg.register_parented(var, parent_config[CONF_MAIDSITE_DESK_ID])
cg.add(getattr(hub, f"set_{key}_number")(var))
@@ -0,0 +1,14 @@
#include "maidsite_desk_number.h"
namespace esphome
{
namespace maidsite_desk
{
void MaidsiteDeskNumber::control(float value)
{
this->publish_state(value);
this->parent_->number_control(this, value);
}
} // namespace maidsite_desk
} // namespace esphome
@@ -0,0 +1,19 @@
#pragma once
#include "esphome/components/number/number.h"
#include "../maidsite_desk.h"
namespace esphome
{
namespace maidsite_desk
{
class MaidsiteDeskNumber : public number::Number, public Parented<MaidsiteDeskComponent>
{
public:
MaidsiteDeskNumber() = default;
protected:
void control(float value) override;
};
} // namespace maidsite_desk
} // namespace esphome
+82
View File
@@ -0,0 +1,82 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor
from esphome.const import (
UNIT_CENTIMETER,
UNIT_PERCENT,
)
from . import MaidsiteDeskComponent, CONF_MAIDSITE_DESK_ID
CONF_UNIT = "unit"
CONF_HEIGHT_ABS = "height_abs"
CONF_HEIGHT_PCT = "height_pct"
CONF_HEIGHT_MIN = "height_min"
CONF_HEIGHT_MAX = "height_max"
CONF_POSITION_M1 = "position_m1"
CONF_POSITION_M2 = "position_m2"
CONF_POSITION_M3 = "position_m3"
CONF_POSITION_M4 = "position_m4"
TYPES = [
CONF_UNIT,
CONF_HEIGHT_ABS,
CONF_HEIGHT_PCT,
CONF_HEIGHT_MIN,
CONF_HEIGHT_MAX,
CONF_POSITION_M1,
CONF_POSITION_M2,
CONF_POSITION_M3,
CONF_POSITION_M4,
]
CONFIG_SCHEMA = cv.All(
cv.Schema(
{
cv.GenerateID(CONF_MAIDSITE_DESK_ID): cv.use_id(MaidsiteDeskComponent),
cv.Optional(CONF_UNIT): sensor.sensor_schema(),
cv.Optional(CONF_HEIGHT_ABS): sensor.sensor_schema(
accuracy_decimals=2,
unit_of_measurement=UNIT_CENTIMETER,
),
cv.Optional(CONF_HEIGHT_PCT): sensor.sensor_schema(
accuracy_decimals=2,
unit_of_measurement=UNIT_PERCENT,
),
cv.Optional(CONF_HEIGHT_MIN): sensor.sensor_schema(
accuracy_decimals=2,
unit_of_measurement=UNIT_CENTIMETER,
),
cv.Optional(CONF_HEIGHT_MAX): sensor.sensor_schema(
accuracy_decimals=2,
unit_of_measurement=UNIT_CENTIMETER,
),
cv.Optional(CONF_POSITION_M1): sensor.sensor_schema(
accuracy_decimals=2,
unit_of_measurement=UNIT_CENTIMETER,
),
cv.Optional(CONF_POSITION_M2): sensor.sensor_schema(
accuracy_decimals=2,
unit_of_measurement=UNIT_CENTIMETER,
),
cv.Optional(CONF_POSITION_M3): sensor.sensor_schema(
accuracy_decimals=2,
unit_of_measurement=UNIT_CENTIMETER,
),
cv.Optional(CONF_POSITION_M4): sensor.sensor_schema(
accuracy_decimals=2,
unit_of_measurement=UNIT_CENTIMETER,
),
}
).extend(cv.COMPONENT_SCHEMA)
)
async def to_code(config):
hub = await cg.get_variable(config[CONF_MAIDSITE_DESK_ID])
for key in TYPES:
await setup_conf(config, key, hub)
async def setup_conf(parent_config, key, hub):
if child_config := parent_config.get(key):
var = await sensor.new_sensor(child_config)
cg.add(getattr(hub, f"set_{key}_sensor")(var))
@@ -1,184 +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_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]))
@@ -1,381 +0,0 @@
#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<float>((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);
}
}
}
// 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::add_button(button::Button *btn, int action)
{
btn->add_on_press_callback([this, action]() { this->button_press_action(action); });
}
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
@@ -1,105 +0,0 @@
#pragma once
#include <future>
#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
@@ -1,37 +0,0 @@
#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
@@ -1,35 +0,0 @@
#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