psieg / Lightpack

Lightpack and Prismatik open repository
GNU General Public License v3.0
1.57k stars 189 forks source link

Dim white sections while maintaining brightness of non-white sections #342

Open zalerapraxis opened 4 years ago

zalerapraxis commented 4 years ago

Sorry for the title. I'll try to explain.

My idea is a feature to lower the brightness of white or near-white LEDs without affecting the brightness of non-white LEDs or compromising their color. My goal with this idea is to reduce heat generated by sections of an LED strip that get set to white for extended periods of time - sort of a "LED saver" function.

Hypothetically, given a screen displaying a blue sky with clouds where Prismatik is set to a brightness level of 100%, the LEDs representing the sections of blue sky would remain at 100% brightness, while the LEDs representing white clouds would be dimmed to some (perhaps configurable) degree.

I have a high-density strip of WS2813s, 144 LEDs per meter, and they tend to get quite hot when they're set to white or near-white - for example, a bright sky in a game or movie, or a webpage background. I've burnt out LEDs in two different genuine WS2812B strips due to heat, as my setup is less-than-ideal for heat dissipation. I've settled for turning my LEDs off via hotkey when I expect the system to be displaying white for extended periods, but I'd like to see if a more elegant solution could be achieved.

I implemented something like this myself, messing around with the code that handles the over-brighten feature here: https://github.com/psieg/Lightpack/blob/21dfa456b3fcf9b3a3c165b5905f61b91f5f7d3c/Software/src/GrabManager.cpp#L462

by adding this after the over-brighten code:

if (true) // introduce var
{
    int dRed = qRed(newColor);
    int dGreen = qGreen(newColor);
    int dBlue = qBlue(newColor);
    int dCombined = dRed + dGreen + dBlue;

    // these values are 255/255/255 after 3450K color temperature adjustment
    int redMax = 255;
    int greenMax = 192;
    int blueMax = 132;
    int combinedMax = redMax + greenMax + blueMax;

    // threshold adjustable by user?
    double thresholdPercent = 0.75;

    int combinedThreshold = combinedMax * thresholdPercent;

    if (dCombined > combinedThreshold) {
        double percentReduction = (((double) dCombined / (double) combinedMax) - thresholdPercent);
        double modifier = 1 - percentReduction;

        newColor = qRgb(dRed * modifier, dGreen * modifier, dBlue * modifier);
    }
}

The maximum value in this snippet would normally be 255/255/255, though I set it to 255/192/132 as that's pure white after factoring in my color temperature adjustment. I'm not sure how you'd want to approach this in an ideal implementation.

It seems to work in practice, but there may be a better solution.

zomfg commented 4 years ago

Good idea. I pushed a more "integrated" version (see #352) Here's a test build, it'll be "Brightness cap" in "Device" tab.