OK whew, finally we are ready to make our Circuit Playground Express zapper. There's no hardware changes or add-ons, you can use the CPX exactly as is thanks to the built-in IR emitter. You'll just need to save this code as main.py
on your CPX:
# SPDX-FileCopyrightText: 2018 Limor Fried for Adafruit Industries # # SPDX-License-Identifier: MIT import array import time import board import pulseio from digitalio import DigitalInOut, Direction, Pull # pylint: disable=eval-used # Switch to select 'stealth-mode' switch = DigitalInOut(board.SLIDE_SWITCH) switch.direction = Direction.INPUT switch.pull = Pull.UP # Button to see output debug led = DigitalInOut(board.D13) led.direction = Direction.OUTPUT # Speaker as haptic feedback spkr_en = DigitalInOut(board.SPEAKER_ENABLE) spkr_en.direction = Direction.OUTPUT spkr_en.value = True spkr = DigitalInOut(board.SPEAKER) spkr.direction = Direction.OUTPUT # Allow any button to trigger activity! button_a = DigitalInOut(board.BUTTON_A) button_a.direction = Direction.INPUT button_a.pull = Pull.DOWN button_b = DigitalInOut(board.BUTTON_B) button_b.direction = Direction.INPUT button_b.pull = Pull.DOWN while True: # Wait for button press! while not (button_a.value or button_b.value): pass time.sleep(0.5) # Give a half second before starting # gooooo! f = open("/codes.txt", "r") for line in f: code = eval(line) print(code) if switch.value: led.value = True else: spkr.value = True # If this is a repeating code, extract details try: repeat = code["repeat"] delay = code["repeat_delay"] except KeyError: # by default, repeat once only! repeat = 1 delay = 0 # The table holds the on/off pairs table = code["table"] pulses = [] # store the pulses here # Read through each indexed element for i in code["index"]: pulses += table[i] # and add to the list of pulses pulses.pop() # remove one final 'low' pulse with pulseio.PulseOut( board.REMOTEOUT, frequency=code["freq"], duty_cycle=2**15 ) as pulse: for i in range(repeat): pulse.send(array.array("H", pulses)) time.sleep(delay) led.value = False spkr.value = False time.sleep(code["delay"]) f.close()
And save this file as codes.txt on the CPX mini disk drive as well (it contains the 200+ IR codes)
Let's go through what this code actually does!
Stealth Mode
When you're in the field, you may want to avoid having something blinking in your hand. On the other hand, you want to know when its done transmitting so you can move on to the next target. So we use the built in slide switch for 'Stealth Mode':
############## Switch to select 'stealth-mode' switch = DigitalInOut(board.SLIDE_SWITCH) switch.direction = Direction.INPUT switch.pull = Pull.UP # Button to see output debug led = DigitalInOut(board.D13) led.direction = Direction.OUTPUT ############## Speaker as haptic feedback spkr_en = DigitalInOut(board.SPEAKER_ENABLE) spkr_en.direction = Direction.OUTPUT spkr_en.value = True spkr = DigitalInOut(board.SPEAKER) spkr.direction = Direction.OUTPUT
If the switch is one way, the red LED will be used to blink when emitting a code. Flip the switch to have the speaker make a 'tic', a very small sound that you can hear if you're nearby but won't give you away!
Buttons and IR output
We'll use the two buttons to tell when its time to zap! Since its hard to remember which is which while out in the field, we set up both buttons:
############## Allow any button to trigger activity! button_a = DigitalInOut(board.BUTTON_A) button_a.direction = Direction.INPUT button_a.pull = Pull.DOWN button_b = DigitalInOut(board.BUTTON_B) button_b.direction = Direction.INPUT button_b.pull = Pull.DOWN
The built in REMOTEOUT
pin is connected to the IR LED, we just create a PWM output on that pin. Even though we set up the frequency as 38000, we'll change the frequency for each code (thus the variable_frequency=True
)
pwm = pulseio.PWMOut(board.REMOTEOUT, frequency=38000, duty_cycle=2 ** 15, variable_frequency=True) pulse = pulseio.PulseOut(pwm)
Main Loop
Now we're ready. In the main loop, we'll wait for any button press. If we get a press, we pause a moment (to get lined up) and then open that codes.txt
file to read in IR codes!
while True: # Wait for button press! while not (button_a.value or button_b.value): pass time.sleep(0.5) # Give a half second before starting # gooooo! f = open("/codes.txt", "r")
Each line contains that dictionary entry. We use the magical eval() function to convert the text to a Python object. Depending on the switch position we either turn on the LED or give the speaker a pulse high.
for line in f: code = eval(line) print(code) if switch.value: led.value = True else: spkr.value = True
Then we can check the dictionary. Repeating codes have a 'repeat' and 'repeat_delay' entry. If not, we'll assume we're transmitting only once.
# If this is a repeating code, extract details try: repeat = code['repeat'] delay = code['repeat_delay'] except KeyError: # by default, repeat once only! repeat = 1 delay = 0
Then, we can take that code-pair table out, and 'de-index' the table to recreate the original on/off list (we need that list for the pulse
output send
function)
# The table holds the on/off pairs table = code['table'] pulses = [] # store the pulses here # Read through each indexed element for i in code['index']: pulses += table[i] # and add to the list of pulses pulses.pop() # remove one final 'low' pulse
Finally, set the PWM output frequency to whatever the TV is listening for, and send the pulse on/off codes, repeating if desired.
Once done, turn off the LED and speaker, and have one long inter-code delay.
pwm.frequency = code['freq'] for i in range(repeat): pulse.send(array.array('H', pulses)) time.sleep(delay) led.value = False spkr.value = False time.sleep(code['delay'])
And when done, close the file so we can start over, waiting for another button press
f.close()
That's it! You may want to run the code on the REPL the first time, to make sure you've got everything set up.
Note that the IR LED draws a couple hundred milli-Amps when sending IR data, so a good battery pack will help you get that range. You can expect up to 30 feet, depending on your targeting skills!
Text editor powered by tinymce.