This example uses a PyPortal Titano as a remote control for NeoPixels. It uses HTTP which is pretty slow, but MQTT on PyPortals is a bit unreliable at the moment.
For this project, you need:




If the FeatherWing tripler is out of stock, you can also use a FeatherWing Doubler and put Stacking Headers on either the Feather M4 or the AirLift FeatherWing.

First click Download Project Bundle below. This zip file will contain everything you need for this example. However, the files are also in the zip file you downloaded for the FunHouse, so you can get them from either one, just make sure you take the files from the neopixel_remote directory.
# SPDX-FileCopyrightText: 2021 Eva Herrada for Adafruit Industries # SPDX-License-Identifier: MIT """ NeoPixel remote control using PyPortal Titano. Colors used are taken from Adafruit_CircuitPython_LED_Animation library """ import time import math import board import busio from digitalio import DigitalInOut import displayio from adafruit_display_shapes.rect import Rect import adafruit_imageload import adafruit_touchscreen # ESP32 SPI from adafruit_esp32spi import adafruit_esp32spi, adafruit_esp32spi_wifimanager # Import NeoPixel Library import neopixel # Import Adafruit IO HTTP Client from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError ts = adafruit_touchscreen.Touchscreen( board.TOUCH_XL, board.TOUCH_XR, board.TOUCH_YD, board.TOUCH_YU, calibration=((5200, 59000), (5800, 57000)), size=(480, 320), ) RED = 0xFF0000 YELLOW = 0xFF9600 ORANGE = 0xFF2800 GREEN = 0x00FF00 TEAL = 0x00FF78 CYAN = 0x00FFFF BLUE = 0x0000FF PURPLE = 0xB400FF MAGENTA = 0xFF0014 WHITE = 0xFFFFFF BLACK = 0x000000 GOLD = 0xFFDE1E PINK = 0xF15AFF AQUA = 0x32FFFF JADE = 0x00FF28 AMBER = 0xFF6400 colors = [ None, None, GREEN, PURPLE, GOLD, AMBER, None, None, ORANGE, BLUE, BLACK, JADE, None, None, YELLOW, CYAN, WHITE, AQUA, None, None, RED, TEAL, MAGENTA, PINK, ] print(colors) group = displayio.Group() # pyportal_setter.xcf has been included so you can edit the colors used in GIMP, just make sure to # change them here as well background, palette = adafruit_imageload.load( "bmps/pyportal_setter.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette ) tile_grid = displayio.TileGrid(background, pixel_shader=palette) group.append(tile_grid) rect = Rect(0, 0, 160, 320, fill=0x000000) group.append(rect) print(len(group)) # Get wifi details and more from a secrets.py file try: from secrets import secrets except ImportError: print("WiFi secrets are kept in secrets.py, please add them there!") raise # PyPortal ESP32 Setup esp32_cs = DigitalInOut(board.ESP_CS) esp32_ready = DigitalInOut(board.ESP_BUSY) esp32_reset = DigitalInOut(board.ESP_RESET) spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) # Set your Adafruit IO Username and Key in secrets.py # (visit io.adafruit.com if you need to create an account, # or if you need your Adafruit IO key.) ADAFRUIT_IO_USER = secrets["aio_username"] ADAFRUIT_IO_KEY = secrets["aio_key"] # Create an instance of the Adafruit IO HTTP client io = IO_HTTP(ADAFRUIT_IO_USER, ADAFRUIT_IO_KEY, wifi) try: # Get the 'temperature' feed from Adafruit IO neopixel_feed = io.get_feed("neopixel") except AdafruitIO_RequestError: neopixel_feed = io.create_new_feed("neopixel") board.DISPLAY.show(group) print("ready") last_color = 257 last_index = 0 while True: p = ts.touch_point if p: x = math.floor(p[0] / 80) y = math.floor(p[1] / 80) index = 6 * y + x # Used to prevent the touchscreen sending incorrect results if last_index == index: color = colors[index] if colors[index]: group[1].fill = color if last_color != color: color_str = "#{:06x}".format(color) print(color_str) io.send_data(neopixel_feed["key"], color_str) last_color = color last_index = index time.sleep(0.1)
First, you'll need to copy over the following libraries to your PyPortal Titano:
- adafruit_display_shapes/
- adafruit_imageload/
- adafruit_io/
- adafruit_esp32spi/
- adafruit_requests.mpy
- adafruit_touchscreen.mpy
- neopixel.mpy
After you've done that, rename neopixel_remote.py to code.py and put it on the PyPortal.
Next, make a new folder on your PyPortal named bmps and put pyportal_setter.bmp inside it.
Finally, copy over your secrets.py file.
When you've done all this, your PyPortal should look like this and you should be able to tap a square and have the top of the display turn that color as well as see the Adafruit IO color indicator turn that color.
# SPDX-FileCopyrightText: 2021 Dylan Herrada for Adafruit Industries # SPDX-License-Identifier: MIT """ Sets NeoPixel color based on an Adafruit IO feed. Uses: * https://www.adafruit.com/product/3811 * Feather board * https://www.adafruit.com/product/4264 * https://www.adafruit.com/product/2890 If your Feather board has STEMMA QT, you'll need one of these: * https://www.adafruit.com/product/4209 But if it doesn't, use stacking headers on either the Feather or the AirLift FeatherWing """ import board import busio from adafruit_esp32spi import adafruit_esp32spi from adafruit_esp32spi import adafruit_esp32spi_wifimanager import adafruit_esp32spi.adafruit_esp32spi_socket as socket import neopixel import adafruit_minimqtt.adafruit_minimqtt as MQTT from adafruit_io.adafruit_io import IO_MQTT from digitalio import DigitalInOut ### WiFi ### # Get wifi details and more from a secrets.py file try: from secrets import secrets except ImportError: print("WiFi secrets are kept in secrets.py, please add them there!") raise # Change the first number to the pin the data line is plugged in to and the second number # to the number of pixels pixels = neopixel.NeoPixel(board.D5, 300) # If you are using a board with pre-defined ESP32 Pins: esp32_cs = DigitalInOut(board.D13) esp32_ready = DigitalInOut(board.D11) esp32_reset = DigitalInOut(board.D12) spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) """Use below for Most Boards""" status_light = neopixel.NeoPixel( board.NEOPIXEL, 1, brightness=0.2 ) # Uncomment for Most Boards wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) # Define callback functions which will be called when certain events happen. # pylint: disable=unused-argument def connected(client): client.subscribe("neopixel") def subscribe(client, userdata, topic, granted_qos): # This method is called when the client subscribes to a new feed. print("Subscribed to {0} with QOS level {1}".format(topic, granted_qos)) def on_neopixel(client, topic, message): print(message) colors = [ int(message.split("#")[1][i : i + 2], 16) for i in range(0, len(message) - 1, 2) ] print(colors) pixels.fill(colors) # Connect to WiFi print("Connecting to WiFi...") wifi.connect() print("Connected!") # Initialize MQTT interface with the esp interface MQTT.set_socket(socket, esp) # Initialize a new MQTT Client object mqtt_client = MQTT.MQTT( broker="io.adafruit.com", username=secrets["aio_username"], password=secrets["aio_key"], ) # Initialize an Adafruit IO MQTT Client io = IO_MQTT(mqtt_client) io.add_feed_callback("neopixel", on_neopixel) # Connect the callback methods defined above to Adafruit IO io.on_connect = connected io.on_subscribe = subscribe # Connect to Adafruit IO print("Connecting to Adafruit IO...") io.connect() io.get("neopixel") while True: io.loop()
First, copy over the required libraries:
- adafruit_esp32spi/
- adafruit_io/
- adafruit_minimqtt/
- adafruit_requests.mpy
- neopixel.mpy
The code above should already be downloaded. Rename it to code.py and copy it over to your Feather.
After you've copied all that over, copy your secrets.py over and you should be set as far as the files are concerned.
Assembly
Solder the headers that came with each device. Then put the Feather and the AirLift FeatherWing in the FeatherWing Tripler and attach the data wire from the NeoPixel strip (often green. I used one of these to make it a bit easier) to pin D5 (third pin from the end furthest from the USB port of the header with less pins) on the Tripler and then connect the ground wire (usually white or black) to a GND pin on the Tripler.
Afer you've done all this it should look something like this:
Now, connect the NeoPixel strip to a power source. If you have a lot of pixels, use a power supply but if you only have a few, you can get away with connecting it to the USB pin (note: this only works if you're powering the board through USB. If you're powering it with a LiPo this won't work).