Text Editor

Adafruit recommends using the Mu editor for editing your CircuitPython code. You can get more info in this guide.

Alternatively, you can use any text editor that saves simple text files.

Download the Project Bundle

Your project will use a specific set of CircuitPython libraries, .txt files, and the code.py file. To get everything you need, click on the Download Project Bundle link below, and uncompress the .zip file.

Plug the Circuit Playground into your computer via a known good data+power USB cable. Your board should show up in your File Explorer/Finder (depending on your Operating System) as a thumb drive named CIRCUITPY.

Drag the contents of the uncompressed bundle directory onto your board's CIRCUITPY drive, replacing any existing files or directories with the same names, and adding any new ones that are necessary.

# SPDX-FileCopyrightText: 2018 Limor Fried for Adafruit Industries
#
# SPDX-License-Identifier: MIT
# Circuit Playground Bluefruit version 2022 John Park

import array
import time
import board
import pulseio
from digitalio import DigitalInOut, Direction, Pull
from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService
from adafruit_bluefruit_connect.packet import Packet
from adafruit_bluefruit_connect.button_packet import ButtonPacket

# 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
# which pin for IR LED/blaster
ir_pin = board.A2  # JST IR Blaster board
# 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

# BLE setup
ble = BLERadio()
uart_service = UARTService()
advertisement = ProvideServicesAdvertisement(uart_service)

def ir_code_send(code):
    f = open(code, "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(
            ir_pin, 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()


while True:
    ble.name = 'TVRemote'
    ble.start_advertising(advertisement)

    while not ble.connected:
        # Wait for a connection.
        if button_a.value or button_b.value:
            print("All codes")
            time.sleep(0.1)  # wait a moment
            ir_code_send("/full_codes.txt")

    while ble.connected:
        if button_a.value or button_b.value:
            print("all")
            time.sleep(0.1)  # wait a moment
            ir_code_send("/full_codes.txt")
        if uart_service.in_waiting:
            # Packet is arriving.
            packet = Packet.from_stream(uart_service)
            if isinstance(packet, ButtonPacket) and packet.pressed:
                if packet.button == ButtonPacket.UP:
                    print("Select codes")
                    time.sleep(0.1)  # wait a moment
                    ir_code_send("/codes.txt")

                if packet.button == ButtonPacket.DOWN:
                    print("All codes")
                    time.sleep(0.1)  # wait a moment
                    ir_code_send("/full_codes.txt")

                elif packet.button == ButtonPacket.BUTTON_1:
                    print("Sony power")
                    time.sleep(0.1)  # wait a moment
                    ir_code_send("/sony_pwr.txt")

                elif packet.button == ButtonPacket.BUTTON_2:
                    print("Toshiba power")
                    time.sleep(0.1)  # wait a moment
                    ir_code_send("/toshiba_pwr.txt")

Use the TV Zapper

To use the Zapper, you can simply press either button on the Circuit Playground Bluefruit and point the emitter at the target TVs. Once the proper code is sent, ZAP! The TV will power off! (Or on, if it was already off).

To use it in BLE mode, connected from the Bluefruit mobile app, and use the controller buttons. See this guide for step-by-step instructions on using the Bluefruit Connect app.

  • Up sends the codes in codes.txt
  • Down sends the codes defined in the file full_codes.txt
  • Left sends the Sony power code.
  • Right sends a Toshiba power code.

See the alert box below on how to make your own custom code assignments.

You can figure out which codes to use for particular TV sets by simply running the full_codes.txt function and counting how many tries it took to get to the TV you want. Then copied that line of code into its own text file, for example sony_pwr.txt in the project bundle.

This section of the main TV Zapper guide shows how most of the code works in this project. The main differences here are the use of the IR breakout board, and the Bluetooth functionality.

Libraries

Additional libraries used are related to adafuit_ble and adafruit_bluefruit_connect:

from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService
from adafruit_bluefruit_connect.packet import Packet
from adafruit_bluefruit_connect.button_packet import ButtonPacket

IR Pin

The IR emitter breakout is connected on pin A2:

ir_pin = board.A2  # JST IR Blaster board

IR Code Send Function

The ir_code_send() function is used to open up the requested text file and then emit the relevant code pulses. It will be called by the button presses and Bluefruit buttons to run different code text files.

def ir_code_send(code):
    f = open(code, "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(
            ir_pin, 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()

Main Loop

Then main loop advertises the BLE and then waits for a connection. While it is waiting, you can still use the buttons to send all codes.

while True:
    ble.name = 'TVRemote'
    ble.start_advertising(advertisement)

    while not ble.connected:
            # Wait for a connection.
            if button_a.value or button_b.value:
                print("All codes")
                time.sleep(0.1)  # wait a moment
                ir_code_send("/full_codes.txt")
            pass

Once connected, the physical buttons on the Circuit Playground Bluefruit still work, but now the button packets from the Bluefruit app are also used to call different IR code send text files.

while ble.connected:
        if button_a.value or button_b.value:
            print("all")
            time.sleep(0.1)  # wait a moment
            ir_code_send("/full_codes.txt")
        if uart_service.in_waiting:
            # Packet is arriving.
            packet = Packet.from_stream(uart_service)
            if isinstance(packet, ButtonPacket) and packet.pressed:
                if packet.button == ButtonPacket.UP:
                    print("Select codes")
                    time.sleep(0.1)  # wait a moment
                    ir_code_send("/codes.txt")

                if packet.button == ButtonPacket.DOWN:
                    print("All codes")
                    time.sleep(0.1)  # wait a moment
                    ir_code_send("/full_codes.txt")

                elif packet.button == ButtonPacket.BUTTON_1:
                    print("Sony power")
                    time.sleep(0.1)  # wait a moment
                    ir_code_send("/sony_pwr.txt")

                elif packet.button == ButtonPacket.BUTTON_2:
                    print("Toshiba power")
                    time.sleep(0.1)  # wait a moment
                    ir_code_send("/toshiba_pwr.txt")

This guide was first published on Dec 07, 2022. It was last updated on Mar 29, 2024.

This page (Code the BLE TV Zapper) was last updated on Mar 28, 2024.

Text editor powered by tinymce.