IR Receiving

🎮 READ · Capture the Secret Codes
Module Goal: decode invisible light. Every button on the remote flashes a secret ID in infrared too fast for your eyes, perfect for this receiver. Today you capture the codes, name the buttons, and finish by cracking a secret combination vault.
The remote needs no wiring it is a commercial device, already programmed by its factory. Your receiver is the programmable half of the pair.
📦 CONCEPT BOX The secret language of the remote
When you press a button, the remote's infrared LED flashes invisible light in a precise pattern a burst of flashes and pauses, like a flashlight doing Morse code at super speed. That pattern IS the button's identity: button 1 always sends the same pattern; button OK always sends a different one.
Your receiver watches for that light, measures the flashes, and decodes the pattern into a number the code. Your course reads it as a hex-command: a number written with the digits 0–9 plus A–F (hexadecimal the math_dec block can convert numbers to this format).
Two honest facts about the protocol (called NEC):
- Holding a button down does NOT send the code once it repeats it automatically, many times per second. You will see this yourself.
- Sunlight and some lamps contain infrared too the receiver can be "fooled" by bright light. point it away from windows when testing.
Goal:
press buttons and watch their secret codes appear then verify the table above with your own eyes.
Concepts:
IR Reception · Hexadecimal Codes · Detective Verification
import irremote # Controls the infrared receiver
import time # Controls pauses and timing
# Sets up ir_rx as the infrared receiver
# pin26 corresponds to D2 on the Sensor Shield V5.0
ir_rx = irremote.NEC_RX(26, 8)
print("=== CODE CAPTURE ===") # Title
print("Point the remote at the receiver and press buttons!") # Instructions
while True: # Listen forever
if ir_rx.any(): # Is there a signal waiting to be read?
b0 = ir_rx.code[0] # Byte 0 of the received message
b1 = ir_rx.code[2] # Byte 2 of the received message
print("Code bytes:", hex(b0), hex(b1)) # Show all four in hexadecimal
time.sleep_ms(300) # Ignore window so one press = one report
time.sleep_ms(20) # Fast checking pacebutton Hex-raw hex-command
1 0xba45ff00 0x45
2 0xb946ff00 0x46
3 0xb847ff00 0x47
4 0xbb44ff00 0x44
5 0xbf40ff00 0x40
6 0xbc43ff00 0x43
7 0xf807ff00 0x7
8 0xea15ff00 0x15
9 0xf609ff00 0x9
* 0xe916ff00 0x16
0 0xe619ff00 0x19
# 0xf20dff00 0xd
Up ▲ 0xe718ff00 0x18
Left ◀ 0xf708ff00 0x8
Right ▶ 0xa55aff00 0x5a
Down ▼0xad52ff00 0x52
Ok 0xe31cff00 0x1c
Serial Monitor (press 1, then 2, then Up):
=== CODE CAPTURE ===
Point the remote at the receiver and press buttons!
Code bytes: 0x45 0x0 0x0 0x0 ← button 1!
Code bytes: 0x46 0x0 0x0 0x0 ← button 2!
Code bytes: 0x18 0x0 0x0 0x0 ← Up!
💡 Note: press button 1 and hunt for 0x45 in the four bytes the table's promise, verified. In this library the command sits in the first byte (code[0]); if your hardware shows it in another position, note it and use that index for the rest of the module that flexibility IS the detective ritual. And the hex() around each number is your hexadecimal converter block (from Math): without it, 0x45 would print as plain 69 and the table would look wrong.
🎮 Name the Buttons
Goal:
translate raw codes into button names the remote starts to speak English.
Concepts:
Code Comparison · if / elif Chains · Translation Layer
button Hex-raw hex-command
1 0xba45ff00 0x45
2 0xb946ff00 0x46
3 0xb847ff00 0x47
4 0xbb44ff00 0x44
5 0xbf40ff00 0x40
6 0xbc43ff00 0x43
7 0xf807ff00 0x7
8 0xea15ff00 0x15
9 0xf609ff00 0x9
* 0xe916ff00 0x16
0 0xe619ff00 0x19
# 0xf20dff00 0xd
Up ▲ 0xe718ff00 0x18
Left ◀ 0xf708ff00 0x8
Right ▶ 0xa55aff00 0x5a
Down ▼0xad52ff00 0x52
Ok 0xe31cff00 0x1c
import irremote # Controls the infrared receiver
import time # Controls pauses and timing
# Sets up ir_rx as the infrared receiver
# pin26 corresponds to D2 on the Sensor Shield V5.0
ir_rx = irremote.NEC_RX(26, 8)
print("=== BUTTON NAMES ===") # Title
while True: # Listen forever
if ir_rx.any(): # A button was pressed!
code = ir_rx.code[0] # Read the command byte
if code == 0x45: # Does it match button 1?
print("Button: ONE") # Name it
elif code == 0x46: # Button 2?
print("Button: TWO") # Name it
elif code == 0x18: # The Up arrow?
print("Button: UP") # Name it
elif code == 0x52: # The Down arrow?
print("Button: DOWN") # Name it
elif code == 0x1C: # The OK button?
print("Button: OK the big one in the middle") # Name it
else: # Any other button
print("Unknown code:", hex(code)) # Show the stranger
while ir_rx.any(): # Drain extras
pass # Empty the queue
time.sleep_ms(300) # Ignore window
time.sleep_ms(20) # Checking paceSerial Monitor:
Button: ONE
Button: UP
Button: OK the big one in the middle
Unknown code: 0x5a
💡 Note: the remote only ever sends numbers it is your if/elif chain that gives them names. Unknown codes get shown instead of ignored, so every button on the remote can eventually join your table. Add five more buttons on your own: 3, 4, Left, Right, and # the pattern never changes, only the hex codes.
🎮 New Press vs. Held Button
Goal:
distinguish a NEW press from a HELD button the remote's repeat behavior, tamed.
Concepts:
State Memory with Codes · Repeat Detection · Change Reporting
button Hex-raw hex-command
1 0xba45ff00 0x45
2 0xb946ff00 0x46
3 0xb847ff00 0x47
4 0xbb44ff00 0x44
5 0xbf40ff00 0x40
6 0xbc43ff00 0x43
7 0xf807ff00 0x7
8 0xea15ff00 0x15
9 0xf609ff00 0x9
* 0xe916ff00 0x16
0 0xe619ff00 0x19
# 0xf20dff00 0xd
Up ▲ 0xe718ff00 0x18
Left ◀ 0xf708ff00 0x8
Right ▶ 0xa55aff00 0x5a
Down ▼0xad52ff00 0x52
Ok 0xe31cff00 0x1c
import irremote # Controls the infrared receiver
import time # Controls pauses and timing
# Sets up ir_rx as the infrared receiver
# pin26 corresponds to D2 on the Sensor Shield V5.0
ir_rx = irremote.NEC_RX(26, 8)
last = 0 # Memory of the previous code (0 = nothing yet)
print("Press and HOLD a button to see the repeats!") # The detective hint
while True: # Listen forever
if ir_rx.any(): # A signal arrived
code = ir_rx.code[0] # Read the command byte
if code != last: # Different from the previous press?
print("NEW button:", hex(code)) # A fresh press!
else: # Same code as before
print("...same button still held") # It is the repeat!
last = code # Save this code as the new memory
while ir_rx.any(): # Drain extras
pass # Empty the queue
time.sleep_ms(150) # Short window: repeats still get through
time.sleep_ms(20) # Checking paceSerial Monitor (press 5, then HOLD 5):
NEW button: 0x40
...same button still held
...same button still held
...same button still held
💡 Note: the mystery of the NEC protocol, witnessed live holding sends the code again and again automatically. Your memory variable last now stores a code instead of a signal or a word: same pattern, richer content. Why does this matter? Because a real remote-controlled robot must react to "OK pressed" ONCE, not forty times per second. Repeat awareness = clean control.
🎮 The Button Scoreboard
Goal:
count how many times each of three buttons was pressed a usage scoreboard for the remote.
Concepts:
Parallel Counters · Ignore Windows · Statistics from Play
button Hex-raw hex-command
1 0xba45ff00 0x45
2 0xb946ff00 0x46
3 0xb847ff00 0x47
4 0xbb44ff00 0x44
5 0xbf40ff00 0x40
6 0xbc43ff00 0x43
7 0xf807ff00 0x7
8 0xea15ff00 0x15
9 0xf609ff00 0x9
* 0xe916ff00 0x16
0 0xe619ff00 0x19
# 0xf20dff00 0xd
Up ▲ 0xe718ff00 0x18
Left ◀ 0xf708ff00 0x8
Right ▶ 0xa55aff00 0x5a
Down ▼0xad52ff00 0x52
Ok 0xe31cff00 0x1c0 0x1c
import irremote # Controls the infrared receiver
import time # Controls pauses and timing
# Sets up ir_rx as the infrared receiver
# pin26 corresponds to D2 on the Sensor Shield V5.0
ir_rx = irremote.NEC_RX(26, 8)
count1 = 0 # Counter for button 1
count2 = 0 # Counter for button 2
count3 = 0 # Counter for button 3
print("=== REMOTE SCOREBOARD ===") # Title
print("Count presses on buttons 1, 2 and 3!") # The rules
while True: # Count forever
if ir_rx.any(): # A press arrived
code = ir_rx.code[0] # Read the command byte
if code == 0x45: # Button 1?
count1 += 1 # Its counter grows
print("ONE! (", count1, "total )") # Live report
elif code == 0x46: # Button 2?
count2 += 1 # Its counter grows
print("TWO! (", count2, "total )") # Live report
elif code == 0x47: # Button 3?
count3 += 1 # Its counter grows
print("THREE! (", count3, "total )") # Live report
while ir_rx.any(): # Drain the repeat copies
pass # Empty the queue
time.sleep_ms(400) # Ignore window: one press = one point
time.sleep_ms(20) # Checking paceSerial Monitor:
ONE! ( 1 total )
TWO! ( 1 total )
ONE! ( 2 total )
THREE! ( 1 total )
💡 Note: three counters in parallel the joystick scoreboard pattern (Module 25), now driven by invisible light. The 400 ms ignore window is doing silent work: NEC repeats arrive about 10 times per second while held, and without the window one hold would score ten points. Also try the experiment: which button does your thumb reach fastest? Ergonomics hides in scoreboards.
🎮 The Secret Vault
Goal:
a combination lock made of light. A classmate secretly sets a 3-button code (for example 1 → 2 → 3). Press the buttons in the right ORDER to crack the vault; one wrong button resets the sequence. Who cracks it fastest?
Concepts:
Sequence Detection · Progress Memory · Reset Logic · Game Design
button Hex-raw hex-command
1 0xba45ff00 0x45
2 0xb946ff00 0x46
3 0xb847ff00 0x47
4 0xbb44ff00 0x44
5 0xbf40ff00 0x40
6 0xbc43ff00 0x43
7 0xf807ff00 0x7
8 0xea15ff00 0x15
9 0xf609ff00 0x9
* 0xe916ff00 0x16
0 0xe619ff00 0x19
# 0xf20dff00 0xd
Up ▲ 0xe718ff00 0x18
Left ◀ 0xf708ff00 0x8
Right ▶ 0xa55aff00 0x5a
Down ▼0xad52ff00 0x52
Ok 0xe31cff00 0x1c
import irremote # Controls the infrared receiver
import time # Controls pauses and timing
# Sets up ir_rx as the infrared receiver
# pin26 corresponds to D2 on the Sensor Shield V5.0
ir_rx = irremote.NEC_RX(26, 8)
print("=== THE SECRET VAULT ===") # Title
print("Crack the 3-button code in the right order!") # The rules
progress = 0 # How many correct keys in a row (0 to 3)
attempts = 0 # Counts how many times the vault was cracked
while True: # Guard the vault forever
if ir_rx.any(): # A key was pressed
code = ir_rx.code[0] # Read the command byte
if progress == 0 and code == 0x45: # Waiting for key 1... and it was button 1!
progress = 1 # First key accepted
print("Key 1... accepted. Keep going...") # Suspense
elif progress == 1 and code == 0x46: # Waiting for key 2... button 2!
progress = 2 # Second key accepted
print("Key 2... accepted. One more...") # More suspense
elif progress == 2 and code == 0x47: # Waiting for key 3... button 3!
attempts += 1 # The vault opens one more crack
print(">>> VAULT OPEN! Cracked", attempts, "time(s)!") # THE REVEAL
progress = 0 # Lock it again for the next player
else: # Any wrong button at any moment
if progress > 0: # Only nag if a sequence was in progress
print("Wrong key! Sequence reset.") # The reset
progress = 0 # Back to square one
while ir_rx.any(): # Drain repeats
pass # Empty the queue
time.sleep_ms(400) # Ignore window
time.sleep_ms(20) # Checking paceSerial Monitor:
=== THE SECRET VAULT ===
Crack the 3-button code in the right order!
Key 1... accepted. Keep going...
Wrong key! Sequence reset.
Key 1... accepted. Keep going...
Key 2... accepted. One more...
>>> VAULT OPEN! Cracked 1 time(s)!
💡 Note: the vault's brain is one variable progress that remembers how far into the secret you are. Every press is tested against ONE expected key, chosen by where you are in the sequence; any mistake collapses the progress to zero. This is exactly how real combination locks, phone unlock patterns and cheat codes in video games work: a sequence is just progress + expectation. Change the code by editing three hex numbers then let a classmate set a code YOUR team must crack. The IR family is complete: invisible light in, meaning out.
