Have you ever lost or broken a TV remote before it's time? Have you ever wanted to spice up the way you change channels or inputs on your TV? Have you got a greedy housemate who always steals the remote off you? If any of these are the case, you can learn to program your own TV remote using an Adafruit Circuit Playground Express! The onboard IR receiver (RX) and transmitter (TX) will be used to save and emulate the signals from the original remote to your TV or IR enabled device. If you haven't played with an Adafruit board before the CPX is a great place to start.
Recording Signals for your TV
Before we can start sending signals to your TV we need to know what data they should contain. The program we will upload to the CPX requires the pulseio, board, adafruit_circuitplayground libraries that are available from our CircuitPython on Circuit Playground Express tutorial however we will also require an additional library to make the IR encoding/decoding easier. This library is called adafruit_irremote and can be obtained from the Adafruit IR Remote GitHub Repository. After downloading and unzipping this file, navigate to the \lib folder and then copy the 'adafruit_irremote.mpy' file to the Circuit Playground Express' \lib directory. The board will now have access to the adafruit_irremote library which can be tested by typing 'import adafruit_irremote' in the REPL when the board is connected.
Now that we have the necessary libraries, we need to record some control signals! To record this data, we'll be setting up the IR receiver on your Circuit Playground Express and using your TV remote or remote emulator to send some signals. The code below simply reads any incoming IR signals and prints them to the REPL so you can copy and paste them into a text document for later use.
import pulseio import board import adafruit_irremote from adafruit_circuitplayground.express import cpx # Create a 'pulseio' input, to listen to infrared signals on the IR receiver pulsein = pulseio.PulseIn(board.IR_RX, maxlen=120, idle_state=True) # Create a decoder that will take pulses and turn them into numbers decoder = adafruit_irremote.GenericDecode() while True: pulses = decoder.read_pulses(pulsein) try: # Attempt to convert received pulses into 4 bytes received_code = decoder.decode_bits(pulses, debug=False) except adafruit_irremote.IRNECRepeatException: # We got an unusual short code, probably a 'repeat' signal print("NEC repeat!") continue except adafruit_irremote.IRDecodeException as e: # Something got distorted or maybe its not an NEC-type remote? print("Failed to decode: ", e.args) continue # Print the received code to the REPL print("NEC Infrared code received: ", received_code)
The format of these signals should be four bytes separated by commas in square brackets, e.g. [250, 0, 124, 30].
Sending Signals to your TV
Now that we have our signals in a text file (hopefully labelled), we can send this data using the same libraries as before! The code for this (set to my TV's codes) is below.
# Import the relevant libraries import time # For sleep between transmitting data import board # For accessing the boards pins import pulseio # For creating the IR pulse object import adafruit_irremote # For easily transmitting NEC codes from adafruit_circuitplayground.express import cpx # For accessing the boards functionality # Define the TV's NEC codes Power_Button = [177, 68, 143, 112] Mute_Button = [177, 68, 167, 88] Menu_Button = [177, 68, 63, 192] Source_Button = [177, 68, 135, 120] Up_Button = [177, 68, 221, 34] Left_Button = [177, 68, 199, 56] Okay_Button = [177, 68, 197, 58] Right_Button = [177, 68, 237, 18] Down_Button = [177, 68, 71, 184] Exit_Button = [177, 68, 69, 186] EPG_Button = [177, 68, 7, 248] Volume_Up = [177, 68, 109, 146] Channel_Up = [177, 68, 117, 138] Volume_Down = [177, 68, 61, 194] Channel_Down = [177, 68, 77, 178] # Create the relavent instances PWM = pulseio.PWMOut(board.IR_TX, frequency = 38000, duty_cycle = 2 ** 15) # Defines the IR signal pwm for communication with 50% duty cycle Pulse_Out = pulseio.PulseOut(PWM) # Creates the output pulse instance Signal_Encoder = adafruit_irremote.GenericTransmit(header=[9500, 4500], one=[550, 550], zero=[550, 1700], trail=0) # Defines NEC signals to be sent # Define the capacitive touch sensitivity cpx.adjust_touch_threshold(adjustment = 750) # This is the main loop for the code while True: # If the switch is to the left if cpx.switch: # If A1 is touched send Okay_Button if cpx.touch_A1: cpx.red_led = True Signal_Encoder.transmit(Pulse_Out, Up_Button) cpx.red_led = False time.sleep(0.2) # If A2 is touched send Source_Button if cpx.touch_A2: cpx.red_led = True Signal_Encoder.transmit(Pulse_Out, Down_Button) cpx.red_led = False time.sleep(0.2) # If A3 is touched send Power_Button if cpx.touch_A3: cpx.red_led = True Signal_Encoder.transmit(Pulse_Out, Okay_Button) cpx.red_led = False time.sleep(0.2) # If A4 is touched send Volume_Up if cpx.touch_A4: cpx.red_led = True Signal_Encoder.transmit(Pulse_Out, Volume_Up) cpx.red_led = False time.sleep(0.1) # If A5 is touched send Volume_Down if cpx.touch_A5: cpx.red_led = True Signal_Encoder.transmit(Pulse_Out, Volume_Down) cpx.red_led = False time.sleep(0.1) # If A6 is touched send Channel_Up if cpx.touch_A6: cpx.red_led = True Signal_Encoder.transmit(Pulse_Out, Channel_Up) cpx.red_led = False time.sleep(0.2) # If A7 is touched send Channel_Down if cpx.touch_A7: cpx.red_led = True Signal_Encoder.transmit(Pulse_Out, Channel_Down) cpx.red_led = False time.sleep(0.2) # If Button a is pressed, send Up_Button if cpx.button_a: cpx.red_led = True Signal_Encoder.transmit(Pulse_Out, Source_Button) cpx.red_led = False time.sleep(0.2) # If Button b is pressed, send Down_Button if cpx.button_b: cpx.red_led = True Signal_Encoder.transmit(Pulse_Out, Power_Button) cpx.red_led = False time.sleep(0.2)
As you can see, I have only used 9 signals for this program but have the capacity to add more if I want to implement the slide switch. Once loaded, feel free to test this program on your TV and see if you can change the channel with A6/A7 or change volume with A4/A5. If you can't see a red light from the D13 led your program has either halted which you can debug with the REPL or you need to change the capacitance-sensing value by altering the line
cpx.adjust_touch_threshold(adjustment = 750)
With the switch in the 'True' position, the board will now send an IR signal and the onboard red LED will light up!
Freeforming the Remote
Now we come to the really fun part. If you visit your local hobbyist store you can often find thin, brass rod which is a great conductor. For this project, I used a 1.5mm diameter rod and soldered the 3 ground connections on the board to a copper base plate. I then soldered the capacitive touch ports to a capacitive touch keyboard build for the Circuit Playground Express. Rubber feet on the bottom of the base plate lets the board stand on its own and rubber feet on top of the base plate allow me to place a battery on it for power when a Micro USB connection isn't an option.
There you have it, a functioning TV remote that you've programmed yourself! If you have any troubles or questions don't hesitate to consult our forum and we'll do our best to help you out. If you're interested in learning more, visit our Online Circuit Playground Express Workshop or our other Circuit Playground Express Tutorials.