From f37b8df5921246461c2b50c835fac13be462b786 Mon Sep 17 00:00:00 2001 From: Daniel Eisterhold Date: Mon, 22 Apr 2024 17:21:24 -0500 Subject: [PATCH] Support writing to multiple NeoPixels. --- components/seesaw/light/__init__.py | 8 ++++--- components/seesaw/light/seesaw_neopixel.cpp | 26 +++++++++++++++++---- components/seesaw/light/seesaw_neopixel.h | 19 +++++++++++++-- components/seesaw/seesaw.cpp | 9 +++---- components/seesaw/seesaw.h | 4 ++-- 5 files changed, 51 insertions(+), 15 deletions(-) diff --git a/components/seesaw/light/__init__.py b/components/seesaw/light/__init__.py index 0e4f217..4db7991 100644 --- a/components/seesaw/light/__init__.py +++ b/components/seesaw/light/__init__.py @@ -1,16 +1,17 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import light -from esphome.const import CONF_OUTPUT_ID, CONF_PIN +from esphome.const import CONF_NUM_LEDS, CONF_OUTPUT_ID, CONF_PIN from .. import seesaw_ns, Seesaw, CONF_SEESAW -SeesawNeopixel = seesaw_ns.class_("SeesawNeopixel", light.LightOutput, cg.Component) +SeesawNeopixel = seesaw_ns.class_("SeesawNeopixel", light.AddressableLight) -CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend( +CONFIG_SCHEMA = light.ADDRESSABLE_LIGHT_SCHEMA.extend( { cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(SeesawNeopixel), cv.GenerateID(CONF_SEESAW): cv.use_id(Seesaw), cv.Required(CONF_PIN): cv.int_range(0, 31), + cv.Optional(CONF_NUM_LEDS, default=1): cv.positive_not_null_int, } ) @@ -20,6 +21,7 @@ async def to_code(config): await cg.register_component(var, config) await light.register_light(var, config) seesaw = await cg.get_variable(config[CONF_SEESAW]) + cg.add(var.set_num_leds(config[CONF_NUM_LEDS])) cg.add(var.set_parent(seesaw)) cg.add(var.set_pin(config[CONF_PIN])) diff --git a/components/seesaw/light/seesaw_neopixel.cpp b/components/seesaw/light/seesaw_neopixel.cpp index 7ad63c2..ec39997 100644 --- a/components/seesaw/light/seesaw_neopixel.cpp +++ b/components/seesaw/light/seesaw_neopixel.cpp @@ -7,7 +7,23 @@ namespace seesaw { static const char *const TAG = "seesaw.neopixel"; void SeesawNeopixel::setup() { - this->parent_->setup_neopixel(this->pin_); + this->parent_->setup_neopixel(this->pin_, this->num_leds_); +} + +void SeesawNeopixel::set_num_leds(uint16_t num_leds) { + this->num_leds_ = num_leds; + + // Cleanup if already allocated + if (this->buf_ != nullptr) delete[] this->buf_; + if (this->effect_data_ != nullptr) delete[] this->effect_data_; + + // Byte each for Red, Green, and Blue + this->buf_ = new uint8_t[this->size() * 3]; // NOLINT + this->effect_data_ = new uint8_t[this->size()]; // NOLINT + + // Clear buffer + memset(this->buf_, 0x00, this->size() * 3); + memset(this->effect_data_, 0x00, this->size()); } light::LightTraits SeesawNeopixel::get_traits() { @@ -15,10 +31,12 @@ light::LightTraits SeesawNeopixel::get_traits() { traits.set_supported_color_modes({light::ColorMode::RGB}); return traits; } + void SeesawNeopixel::write_state(light::LightState *state) { - float red, green, blue; - state->current_values_as_rgb(&red, &green, &blue); - this->parent_->color_neopixel(red * 255, green * 255, blue * 255); + for(uint16_t i = 0; i < this->size(); i++) { + auto view = get_view_internal(i); + this->parent_->color_neopixel(i, view.get_red(), view.get_green(), view.get_blue()); + } } } // namespace seesaw diff --git a/components/seesaw/light/seesaw_neopixel.h b/components/seesaw/light/seesaw_neopixel.h index ce674ca..8668ee8 100644 --- a/components/seesaw/light/seesaw_neopixel.h +++ b/components/seesaw/light/seesaw_neopixel.h @@ -1,22 +1,37 @@ #pragma once #include "esphome/core/component.h" -#include "esphome/components/light/light_output.h" +#include "esphome/components/light/addressable_light.h" #include "../seesaw.h" namespace esphome { namespace seesaw { -class SeesawNeopixel : public light::LightOutput, public Component { +class SeesawNeopixel : public light::AddressableLight { public: void setup() override; + void set_num_leds(uint16_t num_leds); void set_parent(Seesaw *parent) { parent_ = parent; } void set_pin(int pin) { this->pin_ = pin; } light::LightTraits get_traits() override; void write_state(light::LightState *state) override; + void clear_effect_data() override { + for (int i = 0; i < this->size(); i++) + this->effect_data_[i] = 0; + } + int32_t size() const override { return this->num_leds_; } protected: Seesaw *parent_; int pin_; + uint8_t *buf_{nullptr}; + uint8_t *effect_data_{nullptr}; + uint16_t num_leds_{0}; + + light::ESPColorView get_view_internal(int32_t index) const override { + uint8_t *base = this->buf_ + (3 * index); + + return light::ESPColorView(base + 0, base + 1, base + 2, nullptr, this->effect_data_ + index, &this->correction_); + } }; } // namespace seesaw diff --git a/components/seesaw/seesaw.cpp b/components/seesaw/seesaw.cpp index 3e03d1f..114e9b1 100644 --- a/components/seesaw/seesaw.cpp +++ b/components/seesaw/seesaw.cpp @@ -166,14 +166,15 @@ void Seesaw::digital_write(uint8_t pin, bool state) { this->write32(SEESAW_GPIO, SEESAW_GPIO_BULK_CLR, pin); } -void Seesaw::setup_neopixel(int pin) { +void Seesaw::setup_neopixel(int pin, uint16_t n) { this->write8(SEESAW_NEOPIXEL, SEESAW_NEOPIXEL_SPEED, 1); - this->write16(SEESAW_NEOPIXEL, SEESAW_NEOPIXEL_BUF_LENGTH, 3); + this->write16(SEESAW_NEOPIXEL, SEESAW_NEOPIXEL_BUF_LENGTH, n * 3); this->write8(SEESAW_NEOPIXEL, SEESAW_NEOPIXEL_PIN, pin); } -void Seesaw::color_neopixel(uint8_t r, uint8_t g, uint8_t b) { - uint8_t buf[7] = {SEESAW_NEOPIXEL, SEESAW_NEOPIXEL_BUF, 0, 0, g, r, b}; +void Seesaw::color_neopixel(uint16_t n, uint8_t r, uint8_t g, uint8_t b) { + uint16_t offset = n * 3; + uint8_t buf[7] = {SEESAW_NEOPIXEL, SEESAW_NEOPIXEL_BUF, (offset >> 8), offset, g, r, b}; this->write(buf, 7); buf[1] = SEESAW_NEOPIXEL_SHOW; this->write(buf, 2); diff --git a/components/seesaw/seesaw.h b/components/seesaw/seesaw.h index 72a7fb3..5246ae4 100644 --- a/components/seesaw/seesaw.h +++ b/components/seesaw/seesaw.h @@ -92,8 +92,8 @@ class Seesaw : public i2c::I2CDevice, public Component { bool digital_read(uint8_t pin); void digital_write(uint8_t pin, bool state); void set_gpio_interrupt(uint32_t pin, bool enabled); - void setup_neopixel(int pin); - void color_neopixel(uint8_t r, uint8_t g, uint8_t b); + void setup_neopixel(int pin, uint16_t n); + void color_neopixel(uint16_t n, uint8_t r, uint8_t g, uint8_t b); protected: i2c::ErrorCode write8(SeesawModule mod, uint8_t reg, uint8_t value);