Skip to content

Commit

Permalink
Support writing to multiple NeoPixels.
Browse files Browse the repository at this point in the history
  • Loading branch information
deisterhold committed Apr 23, 2024
1 parent fbc6e1b commit f37b8df
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 15 deletions.
8 changes: 5 additions & 3 deletions components/seesaw/light/__init__.py
Original file line number Diff line number Diff line change
@@ -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,
}
)

Expand All @@ -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]))

26 changes: 22 additions & 4 deletions components/seesaw/light/seesaw_neopixel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,36 @@ 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() {
auto traits = light::LightTraits();
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
Expand Down
19 changes: 17 additions & 2 deletions components/seesaw/light/seesaw_neopixel.h
Original file line number Diff line number Diff line change
@@ -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
Expand Down
9 changes: 5 additions & 4 deletions components/seesaw/seesaw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions components/seesaw/seesaw.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit f37b8df

Please sign in to comment.