diff --git a/CODEOWNERS b/CODEOWNERS index 46a9ca90fd..410a3b1e3c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -240,7 +240,7 @@ esphome/components/shutdown/* @esphome/core @jsuanet esphome/components/sigma_delta_output/* @Cat-Ion esphome/components/sim800l/* @glmnet esphome/components/sm10bit_base/* @Cossid -esphome/components/sm2135/* @BoukeHaarsma23 +esphome/components/sm2135/* @BoukeHaarsma23 @dd32 @matika77 esphome/components/sm2235/* @Cossid esphome/components/sm2335/* @Cossid esphome/components/sml/* @alengwenus diff --git a/esphome/components/sm2135/__init__.py b/esphome/components/sm2135/__init__.py index 68a9094518..ce78d5337f 100644 --- a/esphome/components/sm2135/__init__.py +++ b/esphome/components/sm2135/__init__.py @@ -8,17 +8,49 @@ from esphome.const import ( ) AUTO_LOAD = ["output"] -CODEOWNERS = ["@BoukeHaarsma23"] +CODEOWNERS = ["@BoukeHaarsma23", "@matika77", "@dd32"] sm2135_ns = cg.esphome_ns.namespace("sm2135") SM2135 = sm2135_ns.class_("SM2135", cg.Component) +CONF_RGB_CURRENT = "rgb_current" +CONF_CW_CURRENT = "cw_current" + +SM2135Current = sm2135_ns.enum("SM2135Current") + +DRIVE_STRENGTHS_CW = { + "10mA": SM2135Current.SM2135_CURRENT_10MA, + "15mA": SM2135Current.SM2135_CURRENT_15MA, + "20mA": SM2135Current.SM2135_CURRENT_20MA, + "25mA": SM2135Current.SM2135_CURRENT_25MA, + "30mA": SM2135Current.SM2135_CURRENT_30MA, + "35mA": SM2135Current.SM2135_CURRENT_35MA, + "40mA": SM2135Current.SM2135_CURRENT_40MA, + "45mA": SM2135Current.SM2135_CURRENT_45MA, + "50mA": SM2135Current.SM2135_CURRENT_50MA, + "55mA": SM2135Current.SM2135_CURRENT_55MA, + "60mA": SM2135Current.SM2135_CURRENT_60MA, +} +DRIVE_STRENGTHS_RGB = { + "10mA": SM2135Current.SM2135_CURRENT_10MA, + "15mA": SM2135Current.SM2135_CURRENT_15MA, + "20mA": SM2135Current.SM2135_CURRENT_20MA, + "25mA": SM2135Current.SM2135_CURRENT_25MA, + "30mA": SM2135Current.SM2135_CURRENT_30MA, + "35mA": SM2135Current.SM2135_CURRENT_35MA, + "40mA": SM2135Current.SM2135_CURRENT_40MA, + "45mA": SM2135Current.SM2135_CURRENT_45MA, +} + + MULTI_CONF = True CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(SM2135), cv.Required(CONF_DATA_PIN): pins.gpio_output_pin_schema, cv.Required(CONF_CLOCK_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_RGB_CURRENT, "20mA"): cv.enum(DRIVE_STRENGTHS_RGB), + cv.Optional(CONF_CW_CURRENT, "10mA"): cv.enum(DRIVE_STRENGTHS_CW), } ).extend(cv.COMPONENT_SCHEMA) @@ -31,3 +63,6 @@ async def to_code(config): cg.add(var.set_data_pin(data)) clock = await cg.gpio_pin_expression(config[CONF_CLOCK_PIN]) cg.add(var.set_clock_pin(clock)) + + cg.add(var.set_rgb_current(config[CONF_RGB_CURRENT])) + cg.add(var.set_cw_current(config[CONF_CW_CURRENT])) diff --git a/esphome/components/sm2135/sm2135.cpp b/esphome/components/sm2135/sm2135.cpp index 8bd64972c9..f9cd4235ed 100644 --- a/esphome/components/sm2135/sm2135.cpp +++ b/esphome/components/sm2135/sm2135.cpp @@ -19,63 +19,125 @@ static const uint8_t SM2135_ADDR_W = 0xC6; // Warm static const uint8_t SM2135_RGB = 0x00; // RGB channel static const uint8_t SM2135_CW = 0x80; // CW channel (Chip default) -static const uint8_t SM2135_10MA = 0x00; -static const uint8_t SM2135_15MA = 0x01; -static const uint8_t SM2135_20MA = 0x02; // RGB max current (Chip default) -static const uint8_t SM2135_25MA = 0x03; -static const uint8_t SM2135_30MA = 0x04; // CW max current (Chip default) -static const uint8_t SM2135_35MA = 0x05; -static const uint8_t SM2135_40MA = 0x06; -static const uint8_t SM2135_45MA = 0x07; // Max value for RGB -static const uint8_t SM2135_50MA = 0x08; -static const uint8_t SM2135_55MA = 0x09; -static const uint8_t SM2135_60MA = 0x0A; - -static const uint8_t SM2135_CURRENT = (SM2135_20MA << 4) | SM2135_10MA; - void SM2135::setup() { ESP_LOGCONFIG(TAG, "Setting up SM2135OutputComponent..."); this->data_pin_->setup(); - this->data_pin_->digital_write(true); + this->data_pin_->digital_write(false); + this->data_pin_->pin_mode(gpio::FLAG_OUTPUT); this->clock_pin_->setup(); - this->clock_pin_->digital_write(true); + this->clock_pin_->digital_write(false); + this->data_pin_->pin_mode(gpio::FLAG_OUTPUT); + + this->data_pin_->pin_mode(gpio::FLAG_PULLUP); + this->clock_pin_->pin_mode(gpio::FLAG_PULLUP); + this->pwm_amounts_.resize(5, 0); } + void SM2135::dump_config() { ESP_LOGCONFIG(TAG, "SM2135:"); LOG_PIN(" Data Pin: ", this->data_pin_); LOG_PIN(" Clock Pin: ", this->clock_pin_); + ESP_LOGCONFIG(TAG, " CW Current: %dmA", 10 + (this->cw_current_ * 5)); + ESP_LOGCONFIG(TAG, " RGB Current: %dmA", 10 + (this->rgb_current_ * 5)); +} + +void SM2135::write_byte_(uint8_t data) { + for (uint8_t mask = 0x80; mask; mask >>= 1) { + if (mask & data) { + this->sm2135_set_high_(this->data_pin_); + } else { + this->sm2135_set_low_(this->data_pin_); + } + + this->sm2135_set_high_(this->clock_pin_); + delayMicroseconds(4); + this->sm2135_set_low_(clock_pin_); + } + + this->sm2135_set_high_(this->data_pin_); + this->sm2135_set_high_(this->clock_pin_); + delayMicroseconds(2); + this->sm2135_set_low_(this->clock_pin_); + delayMicroseconds(2); + this->sm2135_set_low_(this->data_pin_); +} + +void SM2135::sm2135_start_() { + this->sm2135_set_low_(this->data_pin_); + delayMicroseconds(4); + this->sm2135_set_low_(this->clock_pin_); +} + +void SM2135::sm2135_stop_() { + this->sm2135_set_low_(this->data_pin_); + delayMicroseconds(4); + this->sm2135_set_high_(this->clock_pin_); + delayMicroseconds(4); + this->sm2135_set_high_(this->data_pin_); + delayMicroseconds(4); +} + +void SM2135::write_buffer_(uint8_t *buffer, uint8_t size) { + this->sm2135_start_(); + + this->data_pin_->digital_write(false); + for (uint32_t i = 0; i < size; i++) { + this->write_byte_(buffer[i]); + } + + this->sm2135_stop_(); } void SM2135::loop() { if (!this->update_) return; - uint8_t data[6]; + this->sm2135_start_(); + this->write_byte_(SM2135_ADDR_MC); + this->write_byte_(current_mask_); + if (this->update_channel_ == 3 || this->update_channel_ == 4) { // No color so must be Cold/Warm - data[0] = SM2135_ADDR_MC; - data[1] = SM2135_CURRENT; - data[2] = SM2135_CW; - this->write_buffer_(data, 3); + + this->write_byte_(SM2135_CW); + this->sm2135_stop_(); delay(1); - data[0] = SM2135_ADDR_C; - data[1] = this->pwm_amounts_[4]; // Warm - data[2] = this->pwm_amounts_[3]; // Cold - this->write_buffer_(data, 3); + this->sm2135_start_(); + this->write_byte_(SM2135_ADDR_C); + this->write_byte_(this->pwm_amounts_[4]); // Warm + this->write_byte_(this->pwm_amounts_[3]); // Cold } else { // Color - data[0] = SM2135_ADDR_MC; - data[1] = SM2135_CURRENT; - data[2] = SM2135_RGB; - data[3] = this->pwm_amounts_[1]; // Green - data[4] = this->pwm_amounts_[0]; // Red - data[5] = this->pwm_amounts_[2]; // Blue - this->write_buffer_(data, 6); + + this->write_byte_(SM2135_RGB); + this->write_byte_(this->pwm_amounts_[1]); // Green + this->write_byte_(this->pwm_amounts_[0]); // Red + this->write_byte_(this->pwm_amounts_[2]); // Blue } + this->sm2135_stop_(); + this->update_ = false; } +void SM2135::set_channel_value_(uint8_t channel, uint8_t value) { + if (this->pwm_amounts_[channel] != value) { + this->update_ = true; + this->update_channel_ = channel; + } + this->pwm_amounts_[channel] = value; +} + +void SM2135::sm2135_set_low_(GPIOPin *pin) { + pin->digital_write(false); + pin->pin_mode(gpio::FLAG_OUTPUT); +} + +void SM2135::sm2135_set_high_(GPIOPin *pin) { + pin->digital_write(true); + pin->pin_mode(gpio::FLAG_PULLUP); +} + } // namespace sm2135 } // namespace esphome diff --git a/esphome/components/sm2135/sm2135.h b/esphome/components/sm2135/sm2135.h index 0277e9ba1c..a557fc3287 100644 --- a/esphome/components/sm2135/sm2135.h +++ b/esphome/components/sm2135/sm2135.h @@ -1,19 +1,43 @@ #pragma once +#include +#include "esphome/components/output/float_output.h" #include "esphome/core/component.h" #include "esphome/core/hal.h" -#include "esphome/components/output/float_output.h" -#include namespace esphome { namespace sm2135 { +enum SM2135Current : uint8_t { + SM2135_CURRENT_10MA = 0x00, + SM2135_CURRENT_15MA = 0x01, + SM2135_CURRENT_20MA = 0x02, + SM2135_CURRENT_25MA = 0x03, + SM2135_CURRENT_30MA = 0x04, + SM2135_CURRENT_35MA = 0x05, + SM2135_CURRENT_40MA = 0x06, + SM2135_CURRENT_45MA = 0x07, // Max value for RGB + SM2135_CURRENT_50MA = 0x08, + SM2135_CURRENT_55MA = 0x09, + SM2135_CURRENT_60MA = 0x0A, +}; + class SM2135 : public Component { public: class Channel; - void set_data_pin(GPIOPin *data_pin) { data_pin_ = data_pin; } - void set_clock_pin(GPIOPin *clock_pin) { clock_pin_ = clock_pin; } + void set_data_pin(GPIOPin *data_pin) { this->data_pin_ = data_pin; } + void set_clock_pin(GPIOPin *clock_pin) { this->clock_pin_ = clock_pin; } + + void set_rgb_current(SM2135Current rgb_current) { + this->rgb_current_ = rgb_current; + this->current_mask_ = (this->rgb_current_ << 4) | this->cw_current_; + } + + void set_cw_current(SM2135Current cw_current) { + this->cw_current_ = cw_current; + this->current_mask_ = (this->rgb_current_ << 4) | this->cw_current_; + } void setup() override; @@ -40,40 +64,20 @@ class SM2135 : public Component { }; protected: - void set_channel_value_(uint8_t channel, uint8_t value) { - if (this->pwm_amounts_[channel] != value) { - this->update_ = true; - this->update_channel_ = channel; - } - this->pwm_amounts_[channel] = value; - } - void write_bit_(bool value) { - this->clock_pin_->digital_write(false); - this->data_pin_->digital_write(value); - this->clock_pin_->digital_write(true); - } + void set_channel_value_(uint8_t channel, uint8_t value); + void sm2135_set_low_(GPIOPin *pin); + void sm2135_set_high_(GPIOPin *pin); - void write_byte_(uint8_t data) { - for (uint8_t mask = 0x80; mask; mask >>= 1) { - this->write_bit_(data & mask); - } - this->clock_pin_->digital_write(false); - this->data_pin_->digital_write(true); - this->clock_pin_->digital_write(true); - } - - void write_buffer_(uint8_t *buffer, uint8_t size) { - this->data_pin_->digital_write(false); - for (uint32_t i = 0; i < size; i++) { - this->write_byte_(buffer[i]); - } - this->clock_pin_->digital_write(false); - this->clock_pin_->digital_write(true); - this->data_pin_->digital_write(true); - } + void sm2135_start_(); + void sm2135_stop_(); + void write_byte_(uint8_t data); + void write_buffer_(uint8_t *buffer, uint8_t size); GPIOPin *data_pin_; GPIOPin *clock_pin_; + uint8_t current_mask_; + SM2135Current rgb_current_; + SM2135Current cw_current_; uint8_t update_channel_; std::vector pwm_amounts_; bool update_{true}; diff --git a/tests/test3.1.yaml b/tests/test3.1.yaml index 19e4341ee6..0daf4e9671 100644 --- a/tests/test3.1.yaml +++ b/tests/test3.1.yaml @@ -300,6 +300,8 @@ text_sensor: sm2135: data_pin: GPIO12 clock_pin: GPIO14 + rgb_current: 20mA + cw_current: 60mA switch: - platform: template