IR Receiving

🎮 READ · Capture the Secret Codes

Microproject Image

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):

  1. Holding a button down does NOT send the code once it repeats it automatically, many times per second. You will see this yourself.
  2. 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 pace

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

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

Microproject Image

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 pace

Serial 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

Microproject Image

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 pace

Serial 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

Microproject Image

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 pace

Serial 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

Microproject Image

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 pace

Serial 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.