From 1cf3424ebe0b4a91aca016a057a8ad5b70cbb1b6 Mon Sep 17 00:00:00 2001 From: EtienneMD Date: Tue, 10 Jan 2023 20:51:50 -0500 Subject: [PATCH] Add X9C Potentiometer component (#4183) fixes https://github.com/esphome/feature-requests/issues/1270 --- CODEOWNERS | 1 + esphome/components/x9c/__init__.py | 0 esphome/components/x9c/output.py | 46 +++++++++++++++++++ esphome/components/x9c/x9c.cpp | 72 ++++++++++++++++++++++++++++++ esphome/components/x9c/x9c.h | 32 +++++++++++++ esphome/const.py | 2 + tests/test1.yaml | 6 +++ 7 files changed, 159 insertions(+) create mode 100644 esphome/components/x9c/__init__.py create mode 100644 esphome/components/x9c/output.py create mode 100644 esphome/components/x9c/x9c.cpp create mode 100644 esphome/components/x9c/x9c.h diff --git a/CODEOWNERS b/CODEOWNERS index a642274147..a5a4fc2552 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -273,6 +273,7 @@ esphome/components/web_server_base/* @OttoWinter esphome/components/whirlpool/* @glmnet esphome/components/whynter/* @aeonsablaze esphome/components/wl_134/* @hobbypunk90 +esphome/components/x9c/* @EtienneMD esphome/components/xiaomi_lywsd03mmc/* @ahpohl esphome/components/xiaomi_mhoc303/* @drug123 esphome/components/xiaomi_mhoc401/* @vevsvevs diff --git a/esphome/components/x9c/__init__.py b/esphome/components/x9c/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/x9c/output.py b/esphome/components/x9c/output.py new file mode 100644 index 0000000000..44e9d729b3 --- /dev/null +++ b/esphome/components/x9c/output.py @@ -0,0 +1,46 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import pins +from esphome.components import output +from esphome.const import ( + CONF_ID, + CONF_CS_PIN, + CONF_INC_PIN, + CONF_UD_PIN, + CONF_INITIAL_VALUE, +) + +CODEOWNERS = ["@EtienneMD"] + +x9c_ns = cg.esphome_ns.namespace("x9c") + +X9cOutput = x9c_ns.class_("X9cOutput", output.FloatOutput, cg.Component) + +CONFIG_SCHEMA = cv.All( + output.FLOAT_OUTPUT_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(X9cOutput), + cv.Required(CONF_CS_PIN): pins.internal_gpio_output_pin_schema, + cv.Required(CONF_INC_PIN): pins.internal_gpio_output_pin_schema, + cv.Required(CONF_UD_PIN): pins.internal_gpio_output_pin_schema, + cv.Optional(CONF_INITIAL_VALUE, default=1.0): cv.float_range( + min=0.01, max=1.0 + ), + } + ) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await output.register_output(var, config) + + cs_pin = await cg.gpio_pin_expression(config[CONF_CS_PIN]) + cg.add(var.set_cs_pin(cs_pin)) + inc_pin = await cg.gpio_pin_expression(config[CONF_INC_PIN]) + cg.add(var.set_inc_pin(inc_pin)) + ud_pin = await cg.gpio_pin_expression(config[CONF_UD_PIN]) + cg.add(var.set_ud_pin(ud_pin)) + + cg.add(var.set_initial_value(config[CONF_INITIAL_VALUE])) diff --git a/esphome/components/x9c/x9c.cpp b/esphome/components/x9c/x9c.cpp new file mode 100644 index 0000000000..ff7777e71f --- /dev/null +++ b/esphome/components/x9c/x9c.cpp @@ -0,0 +1,72 @@ +#include "x9c.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace x9c { + +static const char *const TAG = "x9c.output"; + +void X9cOutput::trim_value(int change_amount) { + if (change_amount > 0) { // Set change direction + this->ud_pin_->digital_write(true); + } else { + this->ud_pin_->digital_write(false); + } + + this->inc_pin_->digital_write(true); + this->cs_pin_->digital_write(false); // Select chip + + for (int i = 0; i < abs(change_amount); i++) { // Move wiper + this->inc_pin_->digital_write(true); + delayMicroseconds(1); + this->inc_pin_->digital_write(false); + delayMicroseconds(1); + } + + delayMicroseconds(100); // Let value settle + + this->inc_pin_->digital_write(false); + this->cs_pin_->digital_write(true); // Deselect chip safely (no save) +} + +void X9cOutput::setup() { + ESP_LOGCONFIG(TAG, "Setting up X9C Potentiometer with initial value of %f", this->initial_value_); + + this->inc_pin_->get_pin(); + this->inc_pin_->setup(); + this->inc_pin_->digital_write(false); + + this->cs_pin_->get_pin(); + this->cs_pin_->setup(); + this->cs_pin_->digital_write(true); + + this->ud_pin_->get_pin(); + this->ud_pin_->setup(); + + if (this->initial_value_ <= 0.50) { + this->trim_value(-101); // Set min value (beyond 0) + this->trim_value((int) (this->initial_value_ * 100)); + } else { + this->trim_value(101); // Set max value (beyond 100) + this->trim_value((int) (this->initial_value_ * 100) - 100); + } + this->pot_value_ = this->initial_value_; + this->write_state(this->initial_value_); +} + +void X9cOutput::write_state(float state) { + this->trim_value((int) ((state - this->pot_value_) * 100)); + this->pot_value_ = state; +} + +void X9cOutput::dump_config() { + ESP_LOGCONFIG(TAG, "X9C Potentiometer Output:"); + LOG_PIN(" Chip Select Pin: ", this->cs_pin_); + LOG_PIN(" Increment Pin: ", this->inc_pin_); + LOG_PIN(" Up/Down Pin: ", this->ud_pin_); + ESP_LOGCONFIG(TAG, " Initial Value: %f", this->initial_value_); + LOG_FLOAT_OUTPUT(this); +} + +} // namespace x9c +} // namespace esphome diff --git a/esphome/components/x9c/x9c.h b/esphome/components/x9c/x9c.h new file mode 100644 index 0000000000..924460c841 --- /dev/null +++ b/esphome/components/x9c/x9c.h @@ -0,0 +1,32 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/core/hal.h" +#include "esphome/components/output/float_output.h" + +namespace esphome { +namespace x9c { + +class X9cOutput : public output::FloatOutput, public Component { + public: + void set_cs_pin(InternalGPIOPin *pin) { cs_pin_ = pin; } + void set_inc_pin(InternalGPIOPin *pin) { inc_pin_ = pin; } + void set_ud_pin(InternalGPIOPin *pin) { ud_pin_ = pin; } + void set_initial_value(float initial_value) { initial_value_ = initial_value; } + + void setup() override; + void dump_config() override; + + void trim_value(int change_amount); + + protected: + void write_state(float state) override; + InternalGPIOPin *cs_pin_; + InternalGPIOPin *inc_pin_; + InternalGPIOPin *ud_pin_; + float initial_value_; + float pot_value_; +}; + +} // namespace x9c +} // namespace esphome diff --git a/esphome/const.py b/esphome/const.py index 75c686188f..b98126ed34 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -307,6 +307,7 @@ CONF_ILLUMINANCE = "illuminance" CONF_IMPEDANCE = "impedance" CONF_IMPORT_ACTIVE_ENERGY = "import_active_energy" CONF_IMPORT_REACTIVE_ENERGY = "import_reactive_energy" +CONF_INC_PIN = "inc_pin" CONF_INCLUDE_INTERNAL = "include_internal" CONF_INCLUDES = "includes" CONF_INDEX = "index" @@ -742,6 +743,7 @@ CONF_TX_POWER = "tx_power" CONF_TYPE = "type" CONF_TYPE_ID = "type_id" CONF_UART_ID = "uart_id" +CONF_UD_PIN = "ud_pin" CONF_UID = "uid" CONF_UNIQUE = "unique" CONF_UNIT_OF_MEASUREMENT = "unit_of_measurement" diff --git a/tests/test1.yaml b/tests/test1.yaml index 2137fd442d..53ef50d809 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1713,6 +1713,12 @@ output: id: bp5758d_warmwhite channel: 4 current: 10 + - platform: x9c + id: test_x9c + cs_pin: GPIO25 + inc_pin: GPIO26 + ud_pin: GPIO27 + initial_value: 0.5 e131: