Our little creature friend is a great opportunity for rainbow lighting. The rainbow code is often referred to as "rainbow_cycle" for a reason: it is exactly that, a cycle that starts with red, then orange, yellow, green, blue, violet and back to red.

Normally, this cycle must complete before the board can continue to look for inputs. At this point, you must either pause the cycle to wait for input or time the input to happen exactly between cycles. Basically, the rainbow_cycle is blocking - just like we saw with `time.sleep()`.

This won't work for us! Why? Because rainbows are great! We don't want them to stop while we're doing other things. We want to be able to change the brightness and speed of the rainbow without waiting for the cycle to complete.

## Generators to the rescue!

To do this, we're going to use something called a generator. A generator function contains a `yield` statement. You can call `next` on a generator and with every call, it returns a value until it has returned all possible values. The great thing about generators is that they save the state when they `yield` so we can get right back to where we were, as though we never left. This is important for us because we want our cycle to continue while we process other things.

In this example, we're going to combine `time.monotonic()` and dictionaries with the new generators that we're about to learn!

But first, a quick explanation of how we're getting our colors.

## `colorwheel` (or `wheel`) Explained

You have probably come across this code in a number of situations. It's in much of the code that has a rainbow cycle option, and is included in the demos that ship on many of the CircuitPython compatible boards. But how does it work?

```def wheel(pos):
# Input a value 0 to 255 to get a color value.
# The colours are a transition r - g - b - back to r.
if pos < 0 or pos > 255:
return 0, 0, 0
if pos < 85:
return int(255 - pos*3), int(pos*3), 0
if pos < 170:
pos -= 85
return 0, int(255 - pos*3), int(pos*3)
pos -= 170
return int(pos * 3), 0, int(255 - (pos*3))```

The `wheel` code is a function that uses math to allow a single number to represent the `(r, g, b)` tuple that usually represents pixel colors. If you wanted to turn your LEDs red, you'd usually use `cpx.pixels.fill((255, 0, 0))`. However, with `wheel`, if you include the function at the top of your program, you can use `cpx.pixels.fill(wheel(0))`.

Here is what `wheel` looks like graphed out. The x-axis is the number you provide, and the y-axis indicates, based on the color lines, what tuple will be returned. As you can see, if you provide `wheel(112)`, it returns the `(R, G, B)` tuple `(0, 174, 81)`.

Now, if all you're doing is using solid colors, it doesn't make much sense to use `wheel`, because it adds a lot to your code. However, if you want to do a rainbow cycle, `wheel` is the answer. The typical rainbow cycle uses fancy math code to give `wheel` a sequence of numbers from `0` to `255`, to iterate through all the possible colors from red, to green to blue, and back to red again. The rainbow cycle code is designed to continuously do this. So, even though it's only displaying a single color at any given point in time, when it's viewed altogether, it appears to be a beautiful rainbow!

This is important to know because, in our generator code, we're going to use `wheel` to create our rainbow cycle mode, but we're also going to use it to create our individual single color modes. Now that we understand how `wheel` works, the list we use for our color mode sequence generator will make a lot more sense!

## The `next` Step

```# SPDX-FileCopyrightText: 2018 Kattni Rembor for Adafruit Industries
#

import time
from rainbowio import colorwheel

# pylint: disable=stop-iteration-return
def cycle_sequence(seq):
while True:
for elem in seq:
yield elem

def rainbow_lamp(seq):
g = cycle_sequence(seq)
while True:
cpx.pixels.fill(colorwheel(next(g)))
yield

color_sequences = cycle_sequence([
range(256),  # rainbow_cycle
[0],  # red
[10],  # orange
[30],  # yellow
[85],  # green
[137],  # cyan
[170],  # blue
[213],  # purple
[0, 10, 30, 85, 137, 170, 213],  # party mode
])

heart_rates = cycle_sequence([0, 0.5, 1.0])

heart_rate = 0
last_heart_beat = time.monotonic()
next_heart_beat = last_heart_beat + heart_rate

rainbow = None

cpx.detect_taps = 2
cpx.pixels.brightness = 0.2

while True:
now = time.monotonic()

if cpx.tapped or rainbow is None:
rainbow = rainbow_lamp(next(color_sequences))

if cpx.shake(shake_threshold=20):
heart_rate = next(heart_rates)
last_heart_beat = now
next_heart_beat = last_heart_beat + heart_rate

if now >= next_heart_beat:
next(rainbow)
last_heart_beat = now
next_heart_beat = last_heart_beat + heart_rate
```

Load the file on your CPX, and give it at try. It will start with a rainbow. If you double-tap your lamp, it will move to solid red. Double-tap once each to move to yellow, orange, green, cyan, blue and purple. Double-tap one more time to switch to party mode. In party mode, it's easiest to see the changes in speed. While in party mode, shake your lamp. The speed will slow down. Shake it again to slow it down even more. Shake it again, and it will speed up again.

Now let's find out how!

# The Code!

We begin with `imports` and the `wheel` code.

## Generators

First, we're going to first create a special generator, called `cycle_sequence`, that will allow our other generators to continuously cycle through their options.

```def cycle_sequence(seq):
while True:
for elem in seq:
yield elem```

We do this because we're going to have different modes that we would like to repeatedly cycle through. For example, there are two rainbow settings and seven solid colors available for a total of nine color modes. Every call to a generator returns a value until all possible values have been generated. Without `cycle_sequence`, we would get through the nine color modes and the code would stop. With this special generator, the code will allow us to return to the first mode and start again. It's super useful!

Now we can use it to create our rainbow generator, `rainbow_lamp`.

```def rainbow_lamp(seq):
g = cycle_sequence(seq)
while True:
cpx.pixels.fill(wheel(next(g)))
yield```

It is different than the others. It expects to be provided with a sequence, instead of having one to iterate through on its own. `rainbow_lamp` uses `seq` from `cycle_sequence` to iterate through the sequence. The sequence we will provide it is contained within the next generator. We will use the next generator to provide the `(pos)` to `wheel` and create our different color modes.

The next two generators use `cycle_sequence` to iterate through a list of values. The first, `color_sequences`, is a list containing the different `(pos)` position values that will be provided to `wheel`.

```color_sequences = cycle_sequence([
range(256),  # rainbow_cycle
[0],         # red
[10],        # orange
[30],        # yellow
[85],        # green
[137],       # cyan
[170],       # blue
[213],       # purple
[0, 10, 30, 85, 137, 170, 213],  # party mode
])```

The second generator, `heart_rates`, contains the speed of our modes in seconds.

`heart_rates = cycle_sequence([0, 0.5, 1.0])`

To be clear, this is not the speed to cycle between modes - that will be done with user input. This is the speed of the rainbow and party modes. Solid colors do not care about speed, so while the speed exists during those modes, it does not affect them.

Note that `color_sequences` and `heart_rates` are not functions like `rainbow_lamp`, however they are still generators because they use `cycle_sequence`.

## Time

Remember, we learned that when nothing else is going on, we can use `time.sleep()` to control speed, however, if we want to be able to process anything else, we need to use `time.monotonic()`. In this code, we want to be able to process inputs while the rainbow cycle is happening. We will be able to change the speed of the rainbow while the rainbow is going, without halting or resetting the rainbow cycle!

The next section is where we setup what we're going to use with `time.monotonic()`.

```heart_rate = 0
last_heart_beat = time.monotonic()
next_heart_beat = last_heart_beat + heart_rate```

We learned that `time.monotonic()` is all about comparisons, so here we setup the variables we'll be comparing. We set `heart_rate = 0` for use later. Then we set `last_heart_beat = time.monotonic()` and `next_heart_beat = last_heart_beat + heart_rate`.

## Variables

We need to assign a few more things before we get into our loop.

```rainbow = None

cpx.detect_taps = 2
cpx.pixels.brightness = 0.2```

First, we assign `rainbow = None` for later use. Then, we set `cpx.detect_taps = 2` so our code will use a double-tap for the `cpx.tapped` input. Last, we set `cpx.pixels.brightness = 0.2` so the brightness will be low on startup. This way if your CPX resets in the middle of the night, it doesn't come back on super bright!

## The Loop

We begin by setting `now = time.monotonic()` to keep track of current time.

Our first `if` statement has two options.

```    if cpx.tapped or rainbow is None:
rainbow = rainbow_lamp(next(color_sequences))```

One, we double-tap the lamp, and two, `rainbow is None`. If you recall, we assigned `rainbow = None` before the loop. So this statement is effectively saying, "If you double-tap or on startup, do the following." So, if either one of these options are met, we assign `rainbow = rainbow_lamp(next(color_sequences))`. This is where we begin using our generators and is the first time we call `next`! Remember, `rainbow_lamp` expects a sequence, and we are providing it exactly. Each time you double tap, it calls for the `next` value in `color_sequences`, which contains the different color modes. And because we're using our special generator, when we reach the last mode, another double-tap will cycle back to the first mode!

Next, we're using shake as the input to change speeds.

```    if cpx.shake(shake_threshold=20):
heart_rate = next(heart_rates)
last_heart_beat = now
next_heart_beat = last_heart_beat + heart_rate```

Remember, the `heart_rates` generator provides the speeds. We assign `heart_rate` to call the `next` value in `heart_rates`. Then we use our `time.monotonic()` variables to check how much time has passed and set `next_heart_beat = last_heart_beat + heart_rate`. This is used in the last section of code to determine what speed is currently set and use it.

Our last section of code we are determining the speed at which we are calling `next` on `rainbow`. This is how we set the speed of each color mode. Remember, solid colors don't care about speed and simply aren't affected. This speed is important to the rainbow and party modes.

```    if now >= next_heart_beat:
next(rainbow)
last_heart_beat = now
next_heart_beat = last_heart_beat + heart_rate```

We check to see if `now` is greater than or equal to `next_heart_beat` (which we just set to be essentially `now + heart_rate`), and when it is, we call `next` on `rainbow`. This causes the rainbow cycle to move to the next `(pos)` in `wheel`. Lastly, we reset `last_heart_beat` and `next_heart_beat` so we can begin a new comparison, and continue on in our code!

Note:

Pylint ensures that code is written according to a particular standard. The `pylint` comments in the code are there because we chose not to follow the standard for part of our program, in order to keep the code as readable as possible. To learn more, checkout the Pylint documentation.

This guide was first published on Feb 20, 2018. It was last updated on Feb 20, 2018.