A few data types in FancyLED are used for specifying colors.

In these examples, we’ll assume you’ve imported the adafruit_fancyled library as “fancy”:

import adafruit_fancyled.adafruit_fancyled as fancy

RGB Colors

Anyone doing graphics or LED work is likely familiar with the RGB (red, green, blue) color space. In FancyLED these three components are encapsulated in the CRGB class to be passed around as a single entity. The color space in FancyLED is “normalized” — that is, values range from 0.0 to 1.0 (floating-point) rather than the 0 to 255 (integer) usually seen elsewhere. This reduces quantization artifacts when multiple operations are performed on colors.

Image credit: By RGB_farbwuerfel.jpg: Horst Frank RGB_color_solid_cube.png: SharkD derivative work: SharkD  Talk [CC BY-SA 3.0], via Wikimedia Commons

The CRGB constructor accepts three arguments — red, green and blue in that order:

color = fancy.CRGB(1.0, 0.3, 0.0)  # Orange

Values outside the 0.0 to 1.0 range will be clipped to those bounds. However, if you prefer oldschool “0 to 255” colors you can also call the constructor using integers:

color = fancy.CRGB(255, 85, 0)  # Orange

Integer values are immediately converted to the normalized floating-point range on initialization, which can be seen by examining the CRGB instance’s red, green and blue attributes:

>>> print(color.red, color.green, color.blue)
1.0, 0.333333, 0.0

In certain circumstances you might want or need to express an RGB color as a packed integer, usually in hexadecimal format. You’ll see this format sometimes in HTML documents or the Photoshop color picker.

The first pair of hexadecimal digits are the red component (00 to FF), second pair is green, third is blue.

FancyLED can handle RGB colors in this format…

color = 0x6E22CD  # Purple

…but be aware that most of the library’s functions will dissect this value and hand you back a CRGB type with the separate floating-point red, green and blue attributes. CRGB is “more native” to the library.

If you need something converted back into a packed integer value, this can be done through the library’s pack() function:

packed = color.pack()

There’s an inverse function, unpack(), for converting RGB packed integers to CRGB colors:

color = fancy.unpack(0x6E22CD)  # Purple

RGB packed integers are more space-efficient than the CRGB type — say if RAM is a concern and your code has a big list of colors. But integer colors may suffer quantization artifacts after repeated operations…it’s not good to go back and forth a lot.

One place packed RGB values are used is with a corresponding LED-driving library (e.g. NeoPixel, DotStar). Since these libraries don’t recognize CRGB colors natively, you can pack() a color into an integer before assigning it to an LED through the appropriate library. Remember that FancyLED doesn’t actually talk to LEDs itself, it just handles color operations that are common to LED projects.

While technically compatible with RGBW NeoPixels, FancyLED currently only processes colors in RGB space (or HSV, below). The fourth (white) element will usually go unused. You can tack on your own extra W value by passing it to color.pack(W), but the library isn’t “aware” of the white element, and this is the only place it can be incorporated; CRGB colors and palettes don’t allow a fourth value.

HSV Colors

Some folks are more comfortable thinking in the HSV (hue, saturation, value) colorspace, where colors are expressed as a position around the color wheel, how saturated they are away from gray, and their brightness. In FancyLED these are encapsulated in the CHSV class. Again these values are “normalized” — in the 0.0 to 1.0 range — though hue is a special case…

Image credit: By RGB_farbwuerfel.jpg: Horst Frank RGB_color_solid_cube.png: SharkD derivative work: SharkD  Talk (RGB_farbwuerfel.jpg RGB_color_solid_cube.png) [CC BY-SA 3.0], via Wikimedia Commons

Hue isn’t constrained…it can be any value, but it “wraps around” at zero such that fractional values always represent the same hue…for example, -0.8, +0.2 and +1.2 are all the same green-tinged yellow.

Hue 0 is red. Yellow is +1/6, green is 2/6 (or 1/3), cyan is 3/6 (1/2) and so forth.

The CHSV constructor accepts three arguments — hue, saturation and value in that order:

color = fancy.CHSV(0.08, 1.0, 1.0)  # Orange

0–255 integers are also permitted, but like the CRGB constructor these are converted to floating-point internally:

color = fancy.CHSV(20, 255, 255)  # Orange

It’s very common to just want a pure hue (no saturation or brightness adjustment), so it’s okay to pass just a single value; the others will be set to 1.0 defaults:

color = fancy.CHSV(0.08)  # Orange

You can see this in action by then inspecting the CHSV instance’s hue, saturation and value attributes:

>>> print(color.hue, color.saturation, color.value)
0.08, 1.0, 1.0

Types, Conversions and Other Operations

While many FancyLED functions can operate on CHSV colors, some will return a CRGB type. This is normal and by design…some operations just don’t translate directly to HSV colorspace, so the color is converted to RGB first.

FancyLED has no “packed integer” equivalent for HSV colors; that’s an inherently RGB-oriented representation. If you call pack() with a CHSV color, it will be converted to RGB and the return value will be a packed integer representation of the RGB value.

You can manually convert an CHSV color to CRGB by passing the former to the latter’s constructor:

color1 = fancy.CHSV(0.08, 1.0, 1.0)
color2 = fancy.CRGB(color1)

There’s currently no inverse (RGB to HSV) function…if entropy has a direction in FancyLED, it’s toward RGB. Perhaps later, with some decisions made. While HSV to RGB conversion always yields one unique answer, the inverse is sometimes ambiguous — there could be multiple solutions.

You can blend (interpolate) between two colors using the mix() function. This accepts two colors of any supported type (CRGB, CHSV or packed RGB integer…they don’t need to be the same) along with a “weight” of the second color in the mix, in the range 0.0 to 1.0…e.g. 0.0 is 100% the first color, 1.0 is 100% the second color, and 0.5 is an equal mix between the two colors.

color1 = fancy.CHSV(0.08, 1.0, 1.0)
color2 = fancy.CRGB(255, 85, 0)
color3 = fancy.mix(color1, color2, 0.25)  # 75% color1, 25% color2

If both colors are CHSV type, interpolation takes place in HSV space. This is important for giving a “direction” for the hue change, and dealing with ranges that “cross the seam” at hue 0.0. For example, blending from cyan to red…do you want the midpoint color to be green or purple? How you choose your endpoint hues will determine this (0.5 to 0.0 will be greens and yellows along the way…0.5 to 1.0 will be blues and magentas…but the ends will be the same). The return value in this case will also be a CHSV type.

If one or both colors are CRGB type or packed integer, interpolation takes place in RGB space (CHSV color, if any, is converted to RGB first) and the return value is a CRGB type.

mix() can be used to create a color gradient to be issued to LEDs, or to fill a list…

color1 = fancy.CRGB(1.0, 0, 0)    # Red
color2 = fancy.CRGB(1.0, 1.0, 0)  # Yellow
colorlist = [fancy.mix(color1, color2, i / 9) for i in range(10)]

This guide was first published on Feb 01, 2018. It was last updated on Jan 26, 2018.

This page (Colors) was last updated on Jan 25, 2018.

Text editor powered by tinymce.