Makuna / NeoPixelBus

An Arduino NeoPixel support library supporting a large variety of individually addressable LEDs. Please refer to the Wiki for more details. Please use the GitHub Discussions to ask questions as the GitHub Issues feature is used for bug tracking.
GNU Lesser General Public License v3.0
1.18k stars 261 forks source link

Add support for SM16825 chip #740

Closed ubestbsteppin closed 11 months ago

ubestbsteppin commented 11 months ago

Describe the solution you'd like Support for the SM16825 chip in WLED

Additional context I feel like this chip is becoming more popular due to its low power draw and RGBWW support. Many newer Govee LED products use the chip and could be easily converted to be controlled with WLED with proper support for the chip.

Makuna commented 11 months ago

I glanced around and could not find a spec sheet for it. Once I have it, I can add details to how hard/quick this could happen.

ubestbsteppin commented 11 months ago

I glanced around and could not find a spec sheet for it. Once I have it, I can add details to how hard/quick this could happen.

Here's the spec sheet.

subPdf_198006_105604_20220307-012115791-2-2.pdf

Makuna commented 11 months ago

Looks like just a new feature with an exposed post setting. Since I don't have one of these, I would need someone to test it.

16bits per color element, 5 color elements, a 32bit trailing settings block for LED current settings.

ubestbsteppin commented 11 months ago

I can test if you tell me what to test

Makuna commented 11 months ago

Do you know Arduino? I can provide a sketch that you can compile and run on your ESP32.

ALSO, the LED package this comes in, do you know what the ma is for each color of your package? The chip takes a setting for this.

ubestbsteppin commented 11 months ago

Yup that works for me. I don’t know about the LED ma. I guess I could calculate it by measuring the total ma of the strip when all leds are set to the same color and brightness. Would that work? On Oct 26, 2023, at 11:59 PM, Michael Miller @.***> wrote: Do you know Arduino? I can provide a sketch that you can compile and run on your ESP32. ALSO, the LED package this comes in, do you know what the ma is for each color of your package? The chip takes a setting for this.

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you authored the thread.Message ID: @.***>

Makuna commented 11 months ago

Yes, setting them full bright would get us in the ballpark. Often, they are listed with the spec sheet you got or from website you purchased them from.

Makuna commented 11 months ago

https://www.ipixelleds.com/index.php?id=1039

ubestbsteppin commented 11 months ago

Full bright white draws about 2 amps at 36v. That’s across 57 pixels. So roughly 30ma per pixel.

Makuna commented 11 months ago

try full red, then full blue, then full green also.

Note: needed a 16bit per color channel color class (Rgbww80Color) to support the new feature.

charlievogt commented 11 months ago

@Makuna, the Govee Outdoor Pro leds run on this chip. I have a set and would be glad to test or provide any info I can find if that would be of use to you. I'd love to get them running on WLED.

Makuna commented 11 months ago

Once I get it supported in my library and it's tested with Arduino, then we can request for support from WLED. Its close, I will provide a simple Arduino sketch that will do some basic tests soon.

The big thing right now is knowing what the power requirements of your LEDs, as these chips are programmable to the power of the LEDs. Do you know what the Outdoor Pro power usage is?

charlievogt commented 11 months ago

I'll do some testing tomorrow to find out. From the spec sheet linked above, it looks like you'll need separate ma values for each RGB channel still brightness, as well as full cool white and full warm white. Is that correct?

Makuna commented 11 months ago

correct, five channels of mA ratings, RGB, WW, and CW.

charlievogt commented 11 months ago

For the Govee Outdoor Pro (H706A), all of them are right around 18-19 mA, so I would assume row 2 in the current gain table would be best.

R = 17.3 G = 17.6 B = 18 WW = 17.9 CW = 18.8

Note: tested with 10 pixels connected using stock power supply and controller. I divided each result by 10 to produce the numbers above.

Makuna commented 11 months ago

The Sm16825e branch contains the changes. The logic capture of the pin output looks good.

front image tail image

The following sketch will check if it works.


#include <NeoPixelBus.h>

const uint16_t PixelCount = 6; // set this to your strip size, at least 6
const uint8_t PixelPin = 2;  // make sure to set this to the correct pin, ignored for Esp8266
const uint8_t DebugPin = 4;

#define colorSaturation RgbColor::Max

NeoPixelBus<NeoRgbwcSm16825eFeature, NeoWs2812xMethod> strip(PixelCount, PixelPin);

RgbColor red(colorSaturation, 0, 0);
RgbColor green(0, colorSaturation, 0);
RgbColor blue(0, 0, colorSaturation);
Rgbww80Color warmwhite(0,0,0, Rgbww80Color::Max, 0);
Rgbww80Color coolwhite(0,0,0, 0, Rgbww80Color::Max);

RgbColor black(0);

void setup() {
    Serial.begin(115200);
    while (!Serial); // wait for serial attach

    Serial.println();
    Serial.println("Initializing...");
    Serial.flush();

    strip.Begin();
    // set LED current
    NeoRgbwcSm16825eFeature::SettingsObject settings(1,1,1,1,1); // 1 = 20.3 mA
    strip.SetPixelSettings(settings);
    // clear to black
    strip.Show();

    Serial.print(" r ");
    Serial.print(settings.RedTenthMilliAmpere);
    Serial.println(" deci-mA");

    Serial.print(" g ");
    Serial.print(settings.GreenTenthMilliAmpere);
    Serial.println(" deci-mA");

    Serial.print(" b ");
    Serial.print(settings.BlueTenthMilliAmpere);
    Serial.println(" deci-mA");

    Serial.print(" ww ");
    Serial.print(settings.WarmWhiteTenthMilliAmpere);
    Serial.println(" deci-mA");

    Serial.print(" cw ");
    Serial.print(settings.CoolWhiteTenthMilliAmpere);
    Serial.println(" deci-mA");

    pinMode(DebugPin, OUTPUT);
    digitalWrite(DebugPin, LOW);

    Serial.println();
    Serial.println("Running...");
}

void loop() {
    delay(5000);

    Serial.println("Colors R, G, B, WW, CW ...");

    // set the colors, 
    // if they don't match in order, let me know
    strip.SetPixelColor(0, red);
    strip.SetPixelColor(1, green);
    strip.SetPixelColor(2, blue);
    strip.SetPixelColor(3, warmwhite);
    strip.SetPixelColor(strip.PixelCount() - 1, coolwhite); // last pixel

    digitalWrite(DebugPin, HIGH);
    strip.Show();
    digitalWrite(DebugPin, LOW);

    // turn off the pixels
    strip.SetPixelColor(0, black);
    strip.SetPixelColor(1, black);
    strip.SetPixelColor(2, black);
    strip.SetPixelColor(3, black);
    strip.SetPixelColor(strip.PixelCount() - 1, black);
    strip.Show();

    Serial.println("Off ...");
}
charlievogt commented 11 months ago

This worked well, except the warm white and cool white are reversed. The order they displayed is R, G, B, CW, WW.

Makuna commented 11 months ago

Just added the NeoRgbcwSm16825eFeature which places the cool white before the warm white (Rgbcw). Swap the feature and try again.

If everything looks good I will merge into master and create a new release.

charlievogt commented 11 months ago

That does not appear to correct it. Here's the sketch I'm using to test (added a few delays and color cycles so I could see it better).

#include <NeoPixelBus.h>

const uint16_t PixelCount = 10; // set this to your strip size, at least 6
const uint8_t PixelPin = 33;  // make sure to set this to the correct pin, ignored for Esp8266
const uint8_t DebugPin = 4;

#define colorSaturation RgbColor::Max

NeoPixelBus<NeoRgbcwSm16825eFeature, NeoWs2812xMethod> strip(PixelCount, PixelPin);

RgbColor red(colorSaturation, 0, 0);
RgbColor green(0, colorSaturation, 0);
RgbColor blue(0, 0, colorSaturation);
Rgbww80Color warmwhite(0,0,0, Rgbww80Color::Max, 0);
Rgbww80Color coolwhite(0,0,0, 0, Rgbww80Color::Max);

RgbColor black(0);

void setup() {
    Serial.begin(115200);
    while (!Serial); // wait for serial attach

    Serial.println();
    Serial.println("Initializing...");
    Serial.flush();

    strip.Begin();
    // set LED current
    NeoRgbcwSm16825eFeature::SettingsObject settings(1,1,1,1,1); // 1 = 20.3 mA
    strip.SetPixelSettings(settings);
    // clear to black
    strip.Show();

    Serial.print(" r ");
    Serial.print(settings.RedTenthMilliAmpere);
    Serial.println(" deci-mA");

    Serial.print(" g ");
    Serial.print(settings.GreenTenthMilliAmpere);
    Serial.println(" deci-mA");

    Serial.print(" b ");
    Serial.print(settings.BlueTenthMilliAmpere);
    Serial.println(" deci-mA");

    Serial.print(" ww ");
    Serial.print(settings.WarmWhiteTenthMilliAmpere);
    Serial.println(" deci-mA");

    Serial.print(" cw ");
    Serial.print(settings.CoolWhiteTenthMilliAmpere);
    Serial.println(" deci-mA");

    pinMode(DebugPin, OUTPUT);
    digitalWrite(DebugPin, LOW);

    Serial.println();
    Serial.println("Running...");
}

void loop() {
    delay(1000);

    Serial.println("Colors R, G, B, WW, CW ...");

    // set the colors, 
    // if they don't match in order, let me know
    strip.SetPixelColor(0, red);
    strip.SetPixelColor(1, green);
    strip.SetPixelColor(2, blue);
    strip.SetPixelColor(3, warmwhite);
    strip.SetPixelColor(4, coolwhite);
    strip.SetPixelColor(5, red);
    strip.SetPixelColor(6, green);
    strip.SetPixelColor(7, blue);
    strip.SetPixelColor(8, warmwhite);
    strip.SetPixelColor(9, coolwhite);

    digitalWrite(DebugPin, HIGH);
    strip.Show();
    digitalWrite(DebugPin, LOW);
    delay(5000);

    Serial.println("All red ...");

    strip.SetPixelColor(0, red);
    strip.SetPixelColor(1, red);
    strip.SetPixelColor(2, red);
    strip.SetPixelColor(3, red);
    strip.SetPixelColor(4, red);
    strip.SetPixelColor(5, red);
    strip.SetPixelColor(6, red);
    strip.SetPixelColor(7, red);
    strip.SetPixelColor(8, red);
    strip.SetPixelColor(9, red);

    digitalWrite(DebugPin, HIGH);
    strip.Show();
    digitalWrite(DebugPin, LOW);
    delay(1000);

    Serial.println("All green ...");
    strip.SetPixelColor(0, green);
    strip.SetPixelColor(1, green);
    strip.SetPixelColor(2, green);
    strip.SetPixelColor(3, green);
    strip.SetPixelColor(4, green);
    strip.SetPixelColor(5, green);
    strip.SetPixelColor(6, green);
    strip.SetPixelColor(7, green);
    strip.SetPixelColor(8, green);
    strip.SetPixelColor(9, green);

    digitalWrite(DebugPin, HIGH);
    strip.Show();
    digitalWrite(DebugPin, LOW);
    delay(1000);

    Serial.println("All blue ...");
    strip.SetPixelColor(0, blue);
    strip.SetPixelColor(1, blue);
    strip.SetPixelColor(2, blue);
    strip.SetPixelColor(3, blue);
    strip.SetPixelColor(4, blue);
    strip.SetPixelColor(5, blue);
    strip.SetPixelColor(6, blue);
    strip.SetPixelColor(7, blue);
    strip.SetPixelColor(8, blue);
    strip.SetPixelColor(9, blue);

    digitalWrite(DebugPin, HIGH);
    strip.Show();
    digitalWrite(DebugPin, LOW);
    delay(1000);

    Serial.println("All warmwhite ...");
    strip.SetPixelColor(0, warmwhite);
    strip.SetPixelColor(1, warmwhite);
    strip.SetPixelColor(2, warmwhite);
    strip.SetPixelColor(3, warmwhite);
    strip.SetPixelColor(4, warmwhite);
    strip.SetPixelColor(5, warmwhite);
    strip.SetPixelColor(6, warmwhite);
    strip.SetPixelColor(7, warmwhite);
    strip.SetPixelColor(8, warmwhite);
    strip.SetPixelColor(9, warmwhite);

    digitalWrite(DebugPin, HIGH);
    strip.Show();
    digitalWrite(DebugPin, LOW);
    delay(1000);

    Serial.println("All coolwhite ...");
    strip.SetPixelColor(0, coolwhite);
    strip.SetPixelColor(1, coolwhite);
    strip.SetPixelColor(2, coolwhite);
    strip.SetPixelColor(3, coolwhite);
    strip.SetPixelColor(4, coolwhite);
    strip.SetPixelColor(5, coolwhite);
    strip.SetPixelColor(6, coolwhite);
    strip.SetPixelColor(7, coolwhite);
    strip.SetPixelColor(8, coolwhite);
    strip.SetPixelColor(9, coolwhite);

    digitalWrite(DebugPin, HIGH);
    strip.Show();
    digitalWrite(DebugPin, LOW);
    delay(1000);

        // turn off the pixels
    strip.SetPixelColor(0, black);
    strip.SetPixelColor(1, black);
    strip.SetPixelColor(2, black);
    strip.SetPixelColor(3, black);
    strip.SetPixelColor(4, black);
    strip.SetPixelColor(5, black);
    strip.SetPixelColor(6, black);
    strip.SetPixelColor(7, black);
    strip.SetPixelColor(8, black);
    strip.SetPixelColor(9, black);
    strip.SetPixelColor(10, black);
    strip.Show();

    Serial.println("Off ...");
}
charlievogt commented 11 months ago

I'm not sure of the implications, but I switched the definitions of these two lines, and now it's working as expected:

Rgbww80Color coolwhite(0, 0, 0, Rgbww80Color::Max, 0);
Rgbww80Color warmwhite(0, 0, 0, 0, Rgbww80Color::Max);
Makuna commented 11 months ago

The RgbwwColor objects are R,G,B, Warmer White, Cooler White. In that order. It's up to the feature to swap as needed. Warmer and Cooler are relative, if one is neutral white, then it could be warmer than a cool white or cooler than a warm white, depending on which it is paired with.

I found the issue and updated the branch.

Makuna commented 11 months ago

@charlievogt I believe what you were seeing is now fixed and the feature correctly controls the color order. Let me know and I will merge it into master and create a new release.

charlievogt commented 11 months ago

That worked great! The color order is now R G B WW CW.

Sorry for the delayed response--I put the lights up on my house and it took a bit of rework to put an esp32 in line for testing.

Makuna commented 11 months ago

v2.7.7