We've designed the geometric Sjopenna's code to allow control from afar using a mini infrared remote control. Any remote will work if you properly decode the signals. This project is specifically coded for the Adafruit Mini Remote Control. We'll use the CircuitPython IR remote library to read and decode the IR signals.
This project uses many colors associated with different buttons on the IR remote. To keep the code as efficient as possible, we learned how to use a dictionary to eliminate the need for a large block of if
and elif
statements. Now we're going to incorporate that into this code.
Regarding Rainbows
The way that the CircuitPython library for the infrared remote code is written, it is not possible to have a rainbow cycle setting. The library code is blocking which does not allow for the cycle generator that we used for Spoka to function properly. It continues only when the board receives an infrared signal, because the read
function will wait indefinitely until it reads a signal. Due to the significant IR noise present in most environments, at first glance, the rainbow cycle appears to be functioning. As well, if you were to set a rainbow to a particular button, and then hold the button down constantly, it would spam the signal and cycle the rainbow. However, if you cover the IR sensor to block any signals, you'll find that the cycle does not progress. In the event that intermittent noise is received, the progression is jumpy and inconsistent. Given that we cannot predict the amount of IR noise present in any given environment, or expect you to hold down a button forever, we've chosen not to include a rainbow cycle setting in this code.
The Code!
Due to memory constraints we will not be using the same Express
class that we used for Spoka - therefore we will import and initialise each library separately. However, using that class would only eliminate the need to import neopixel
and board
. The Adafruit IR Remote library, adafruit_irremote
, and pulseio
are not included in Express
class and would have been required regardless.
Let's take a look at the code!
# SPDX-FileCopyrightText: 2018 Kattni Rembor for Adafruit Industries # # SPDX-License-Identifier: MIT import adafruit_irremote import board import neopixel import pulseio pixels = neopixel.NeoPixel(board.NEOPIXEL, 10) pulsein = pulseio.PulseIn(board.REMOTEIN, maxlen=120, idle_state=True) decoder = adafruit_irremote.GenericDecode() last_command = None brightness_up = 95 # Up arrow brightness_down = 79 # Down arrow command_to_color = { # button = color 247: (255, 0, 0), # 1 = red 119: (255, 40, 0), # 2 = orange 183: (255, 150, 0), # 3 = yellow 215: (0, 255, 0), # 4 = green 87: (0, 255, 120), # 5 = teal 151: (0, 255, 255), # 6 = cyan 231: (0, 0, 255), # 7 = blue 103: (180, 0, 255), # 8 = purple 167: (255, 0, 20), # 9 = magenta 207: (255, 255, 255), # 0 = white 127: (0, 0, 0), # Play/Pause = off } while True: pulses = decoder.read_pulses(pulsein, max_pulse=5000) command = None try: code = decoder.decode_bits(pulses) if len(code) > 3: command = code[2] print("Decoded:", command) print("-------------") except adafruit_irremote.IRNECRepeatException: # Catches the repeat signal command = last_command except adafruit_irremote.IRDecodeException: # Failed to decode pass if not command: continue last_command = command if command == brightness_up: pixels.brightness += 0.1 elif command == brightness_down: pixels.brightness -= 0.1 elif command in command_to_color: pixels.fill(command_to_color[command])
First we import
the four libraries we'll be using in our code. Then we setup use of those libraries. Now we'll take a look at the next section.
Variables
First we assign last_command
for use later. Then, we assign brightness_up
to the IR command code associated with the up arrow on the IR remote, and brightness_down
to the code for the down arrow.
Dictionary
Here is where we use the dictionary we learned about!
command_to_color = { # button = color 247: (255, 0, 0), # 1 = red 119: (255, 40, 0), # 2 = orange 183: (255, 150, 0), # 3 = yellow 215: (0, 255, 0), # 4 = green 87: (0, 255, 120), # 5 = teal 151: (0, 255, 255), # 6 = cyan 231: (0, 0, 255), # 7 = blue 103: (180, 0, 255), # 8 = purple 167: (255, 0, 20), # 9 = magenta 207: (255, 255, 255), # 0 = white 127: (0, 0, 0), # Play/Pause = off }
The keys
are the IR codes for the eleven buttons we're using and the values
are their associated (r, g, b)
tuples. NeoPixel colors are represented using red, green and blue in values of 0 - 255 to determine the amount of a given color. For example, red is (255, 0, 0)
as it does not contain any green or blue. When red, green and blue are all off, the values are (0, 0, 0)
. We'll call this off, and use it to turn off the LEDs. We've used comments on each line to identify which button on the remote and assigned color the dictionary is referring to.
There are 21 buttons total on the Mini IR remote, and in this code, 13 of them are used. If you wanted to add more colors to this project, you can do so by extending the dictionary. You simply need to choose a button, add that key
to the dictionary, and assign the desired (r, g, b)
value
to use them later in the code. Add a comment to the line to make it easier to remember what button and color you chose!
The Loop
The first two sections of code inside the loop are designed to read the incoming IR signals, decode them, and prepare them for practical use.
while True: pulses = decoder.read_pulses(pulsein, max_pulse=5000) command = None try: code = decoder.decode_bits(pulses) if len(code) > 3: command = code[2] print("Decoded:", command) print("-------------") except adafruit_irremote.IRNECRepeatException: # Catches the repeat signal command = last_command except adafruit_irremote.IRDecodeException: # Failed to decode pass if not command: continue last_command = command
We must deal with the significant amount of IR noise, which shows up as single-value signals. The line if len(code) > 3:
says the signal must be longer longer than three values before we bother to do anything with it. The decoded signal from each button on this remote is four numbers in a list format: [0, 0, 0, 0]
. However, for use, you need only the third number from that list. So, when we get a code of the correct length, we assign command
to be the third value from the list by assigning command = code[2]
. (Remember, in CircuitPython, counting starts with 0
, so the third value is 2
!)
We've left in the two print
statements so you can identify the command code for the unused buttons on the remote in the event you'd like to expand the project to use them.
print("Decoded:", command) print("-------------")
Simply connect to the REPL, press a button, and use the resulting number in your code. If you choose to add to the color dictionary, this is how you can find the IR code to include as the key
!
The last section is where we're telling the code what to do when a particular button is pressed.
When the lamp first lights up, the brightness is set to the maximum. Brightness is a percentage of 0 to 100 represented by a value of 0.0
- 1.0
, and is set using pixels.brightness()
.
if command == brightness_up: pixels.brightness += 0.1 elif command == brightness_down: pixels.brightness -= 0.1
When we press the down arrow, assigned to brightness_down
, it decreases the brightness by 0.1
each time. When we press the up arrow, assigned to brightness_up
, it increases the brightness by 0.1
. This will not increase or decrease it beyond the minimum or maximum.
And finally, we get to call our dictionary!
elif command in command_to_color: pixels.fill(command_to_color[command])
This last elif
statement is checking to make sure that the key
we're using is found in our dictionary. Without this check, your code will throw an error if you pressed a button not in use, as it cannot use a key
or value
that isn't found. The last line uses pixels.fill()
and the values associated with the keys in the dictionary to turn our NeoPixels the chosen colors. This works because pixels.fill()
expects the (r, g, b)
values, we've associated the (r, g, b)
values
the keys
in the dictionary. Like we learned earlier, this is how we take what would have been a huge block of elif
statements and slimmed it down to one!
Now you can control a lamp from across the room with a little IR remote!
Page last edited January 21, 2025
Text editor powered by tinymce.