Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Native SPI RGB LED component #5288

Merged
merged 34 commits into from
Sep 11, 2023
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b9a9cfd
Add testing branch to workflow
clydebarrow Aug 18, 2023
2efdb65
Add workflow
clydebarrow Aug 18, 2023
cc8e4bf
Merge branch 'dev' of https://github.com/esphome/esphome into dev
clydebarrow Aug 18, 2023
1f3fea3
Checkpoint
clydebarrow Aug 20, 2023
75539c9
Align SPI data rates in c++ code with Python code.
clydebarrow Aug 20, 2023
c35cdee
Merge branch 'spirates' into apa102
clydebarrow Aug 20, 2023
aa091e3
Checkpoint
clydebarrow Aug 20, 2023
7dad4b8
Merge branch 'dev' of https://github.com/esphome/esphome into apa102
clydebarrow Aug 20, 2023
101c220
CI fixes
clydebarrow Aug 20, 2023
8380169
Update codeowners
clydebarrow Aug 20, 2023
ec62184
Workflow cleanup
clydebarrow Aug 21, 2023
19dbc22
Rename to spi_rgb_led
clydebarrow Aug 21, 2023
cb7dc32
Rename header file
clydebarrow Aug 21, 2023
62675ae
Clang tidy
clydebarrow Aug 21, 2023
cc33d2e
Merge branch 'dev' into apa102
clydebarrow Aug 21, 2023
a470578
Disable spi after transfer.
clydebarrow Aug 21, 2023
b20b168
Merge branch 'apa102' of https://github.com/clydebarrow/esphome into …
clydebarrow Aug 21, 2023
eb20910
Move enable() to where it belongs
clydebarrow Aug 22, 2023
43a8739
Merge branch 'dev' of https://github.com/esphome/esphome into apa102
clydebarrow Aug 24, 2023
3b1f729
Call spi_setup before enable
clydebarrow Aug 24, 2023
af8d706
Clang tidy
clydebarrow Aug 24, 2023
cfb20ed
Add test
clydebarrow Aug 25, 2023
eb3ea5c
Merge branch 'dev' into apa102
clydebarrow Sep 1, 2023
5ecc32b
Merge branch 'dev' into apa102
clydebarrow Sep 4, 2023
07a78aa
Merge branch 'dev' of https://github.com/esphome/esphome into apa102
clydebarrow Sep 5, 2023
010d669
Rename to spi_led_strip
clydebarrow Sep 5, 2023
eee87f3
Include 'defines.h'
kbx81 Sep 10, 2023
d8f5f9b
Merge branch 'dev' into apa102
kbx81 Sep 10, 2023
a3d3987
Fix CODEOWNERS
kbx81 Sep 10, 2023
2dab7ae
Migrate data rate to new style setting.
clydebarrow Sep 10, 2023
0a6610f
Remove defines.h
clydebarrow Sep 10, 2023
a46b6f2
Fix class name
clydebarrow Sep 10, 2023
95b283e
Fix name in .py
clydebarrow Sep 10, 2023
0e284d9
And more more name tidy up.
clydebarrow Sep 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ esphome/components/socket/* @esphome/core
esphome/components/sonoff_d1/* @anatoly-savchenkov
esphome/components/speaker/* @jesserockz
esphome/components/spi/* @esphome/core
esphome/components/spi_led_strip/* @clydebarrow
esphome/components/sprinkler/* @kbx81
esphome/components/sps30/* @martgras
esphome/components/ssd1322_base/* @kbx81
Expand Down
2 changes: 2 additions & 0 deletions esphome/components/spi_led_strip/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CODEOWNERS = ["@clydebarrow"]
DEPENDENCIES = ["spi"]
26 changes: 26 additions & 0 deletions esphome/components/spi_led_strip/light.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import light
from esphome.components import spi
from esphome.const import CONF_OUTPUT_ID, CONF_NUM_LEDS, CONF_DATA_RATE

spi_rgb_led_ns = cg.esphome_ns.namespace("spi_led_strip")
SpiRgbLed = spi_rgb_led_ns.class_("SpiRgbLed", light.AddressableLight, spi.SPIDevice)

CONFIG_SCHEMA = light.ADDRESSABLE_LIGHT_SCHEMA.extend(
{
cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(SpiRgbLed),
cv.Optional(CONF_NUM_LEDS, default=1): cv.positive_not_null_int,
cv.Optional(CONF_DATA_RATE, default="1MHz"): spi.SPI_DATA_RATE_SCHEMA,
}
).extend(spi.spi_device_schema(False))


async def to_code(config):
var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
cg.add(var.set_num_leds(config[CONF_NUM_LEDS]))
await light.register_light(var, config)
await spi.register_spi_device(var, config)
await cg.register_component(var, config)
spi_data_rate = str(spi.SPI_DATA_RATE_OPTIONS[config[CONF_DATA_RATE]])
cg.add_define("SPIRGBLED_DATA_RATE", cg.RawExpression(spi_data_rate))
91 changes: 91 additions & 0 deletions esphome/components/spi_led_strip/spi_led_strip.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#pragma once

#include "esphome/core/component.h"
kbx81 marked this conversation as resolved.
Show resolved Hide resolved
#include "esphome/core/log.h"
#include "esphome/components/light/addressable_light.h"
#include "esphome/components/spi/spi.h"

namespace esphome {
namespace spi_led_strip {

#ifndef SPIRGBLED_DATA_RATE
#define SPIRGBLED_DATA_RATE spi::DATA_RATE_1MHZ
#endif // SPIRGBLED_DATA_RATE

static const char *const TAG = "spi_led_strip";
class SpiRgbLed : public light::AddressableLight,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_HIGH, spi::CLOCK_PHASE_TRAILING,
SPIRGBLED_DATA_RATE> {
public:
void setup() { this->spi_setup(); }

int32_t size() const override { return this->num_leds_; }

light::LightTraits get_traits() override {
auto traits = light::LightTraits();
traits.set_supported_color_modes({light::ColorMode::RGB});
return traits;
}
void set_num_leds(uint16_t num_leds) {
this->num_leds_ = num_leds;
ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
this->buffer_size_ = num_leds * 4 + 8;
this->buf_ = allocator.allocate(this->buffer_size_);
if (this->buf_ == nullptr) {
esph_log_e(TAG, "Failed to allocate buffer of size %u", this->buffer_size_);
this->mark_failed();
return;
}

this->effect_data_ = allocator.allocate(num_leds);
if (this->effect_data_ == nullptr) {
esph_log_e(TAG, "Failed to allocate effect data of size %u", num_leds);
this->mark_failed();
return;
}
memset(this->buf_, 0xFF, this->buffer_size_);
memset(this->buf_, 0, 4);
}

void dump_config() {
esph_log_config(TAG, "spi_led_strip:");
esph_log_config(TAG, "NumLeds: %d", this->num_leds_);
}

void write_state(light::LightState *state) override {
if (this->is_failed())
return;
if (ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE) {
char strbuf[49];
size_t len = std::min(this->buffer_size_, (size_t) (sizeof(strbuf) - 1) / 3);
memset(strbuf, 0, sizeof(strbuf));
for (size_t i = 0; i != len; i++) {
sprintf(strbuf + i * 3, "%02X ", this->buf_[i]);
}
esph_log_v(TAG, "write_state: buf = %s", strbuf);
}
this->enable();
this->write_array(this->buf_, this->buffer_size_);
this->disable();
}

void clear_effect_data() override {
for (int i = 0; i < this->size(); i++)
this->effect_data_[i] = 0;
}

protected:
light::ESPColorView get_view_internal(int32_t index) const override {
size_t pos = index * 4 + 5;
return {this->buf_ + pos + 2, this->buf_ + pos + 1, this->buf_ + pos + 0, nullptr,
this->effect_data_ + index, &this->correction_};
}

size_t buffer_size_{};
uint8_t *effect_data_{nullptr};
uint8_t *buf_{nullptr};
uint16_t num_leds_;
};

} // namespace spi_led_strip
} // namespace esphome
6 changes: 6 additions & 0 deletions tests/test8.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ light:
name: neopixel-enable
internal: false
restore_mode: ALWAYS_OFF
- platform: spi_led_strip
num_leds: 4
color_correct: [80%, 60%, 100%]
id: rgb_led
name: "RGB LED"
data_rate: 8MHz

spi:
clk_pin: GPIO7
Expand Down