Introduction: The Holi-Tie

About: Just a guy looking to make cool things

This is the Holi-Tie, a festive tie designed to be worn during the holidays. Loosely based on the Ampli-Tie by Becky Stern which uses a Flora board, the Holi-Tie uses a Circuit Python Express (CPX) microcontroller to drive the NeoPixel animations and the music. A button changes between 2 different NeoPixel animations. Capacitive touch pads change the NeoPixel colors and the animation speeds. The other button changes between LED animations and music. The on-board microphone is used to measure ambient noise for the VU meter animation. And the CPX speaker outputs holiday chip tunes.

Everything is coded using the Python programming language running atop the CircuitPython system. It is powered by a 3.7V, 500mAH LiPo battery which was modified to have an on/off switch.

There are two video clips that show the Holi-Tie:

Step 1: Parts and Tools

Parts

When sourcing the parts, it would be wise to buy extras. I had a total of 20 NeoPixels, one of which was broken from the beginning and one I ruined. The Candy Cane tie was so cheap that I bought a second one just in case I ruined the first.

Tools

  • Hot glue gun
  • Soldering station
  • Wire cutters
  • Small knife
  • Multimeter
  • Computer
  • Lighter or heat gun
  • Thread and needle

Step 2: Readying the Tie

The main goal is to get access to the inner tie core and demarcate lines indicating where the LEDs should be positioned.

Step 1: Tie the tie into position

It will difficult to tie the tie when the electronics are in place. So tie the tie so that it looks good and the knot is fairly firm and won't unravel. Then carefully pull the small end of the tie to open up the hole to get the tie over the head. This is the position the tie will be worked on.

There are all kinds of different tie knots. I only know the one that I learned as a kid, the Windsor. It should not matter which knot is used.

Step 2: Open up the back of the tie

Rip open the seams on one side of the tie loop and the logo and then down the center of the tie. Be careful because it has to be sewed back up at the end.

Step 3: Draw lines where the LEDs should be placed

To have the LEDs appear in the white stripe sections of the tie, it is easier to find the center line for each white stripe section on the back of the tie core and then map that to the front of the tie core. Check and double check that the center line is 1) in the center and 2) parallel with the stripe. Fine tuning the LED positions will be possible if they are a little off. But it is best to get it as close to exact now rather than later.

Test the centeredness of the lines by placing LEDs on the lines and laying the stripe fabric on top. Adjust where needed.

Step 3: Attaching the NeoPixels

Basically, we are making our own LED strip. We simply mount the LEDs onto the tie core and then connect them to each other.

Step 1: Adhere the NeoPixels to the tie core

Place a dab of hot glue on the back of the NeoPixel place it on the center lines. For the sections with 3 NeoPixels, vertically align the center NeoPixel and glue those down first. This will make it easier to position the left and right NeoPixel in relation to the center especially given that the width of the tie increases from top to bottom.

Be sure to orient all of the NeoPixels in the same direction, going from bottom left to upper right. If this is not correct, the strip will not work.

A note about the hot glue. It will suffice to get the project completed. As for whether it will last for years to come, one just have to see.

Step 3: Solder the NeoPixels to each other

Because I decided to solder the NeoPixels together instead of using conductive thread, the hole in the NeoPixel pads works against us at bit. Just find a good place on the pad to solder the wire onto. Don't try to fill the hole with solder, but if it happens, it will be OK.

Magnet wire has a thin layer of insulation around a copper core. With a knife, scrape off the insulation just at the ends where they will be soldered. It is best to scrape the entire circumference of the wire.

Step 4: Test connectivity

Use a multimeter to test the connectivity of:

  1. Positive connections. There should be connectivity from tip to tail. Be sure the test connectivity on the pads and not the wire.
  2. Ground connections. Perform the same test but with the ground pads.
  3. Each data line. From one data pad to the next, verify that there is connectivity.

Step 4: Attaching the Circuit Playground Express

The Circuit Playground Express (CPX) is the heart of the system. Adafruit has numerous tutorials for this controller. Later in this instructable, I will highlight a few of the MCU features.

Step 1: Solder the CPX to the bottom tip NeoPixel

Cut appropriate lengths of the magnet wire for the power, ground, and data. Push them through the tie core fabric so that they touch the NeoPixel power, ground, and data pads. Solder them down making sure that the existing wires on the pads are still making good connectivity.

Next turn over the tie core and place the CPX in the desire position. Feed the power wire to the VOUT pad, the ground wire to any ground pad, and the data wire to any I/O pad other than A0. The code I've written uses A3.

Test the connectivity.

Step 2: Tie down the CPX

Using a thread and needle, pick any four equidistant pads and sew them down onto the tie core.

Step 5: Powering the CPX

The CPX does not have an on/off switch. This means that the moment the battery is plugged in, the tie will turn on. This also means that the only way to turn it off is by unplugging the battery, which is a major hassle. A simple solution is to put an off/off switch on the battery.

Step 1: Cut off the 3rd pin on the switch

One of the non-center pins is not needed. Cut it off flush with the body of the switch.

Step 2: Solder the switch in-line a battery lead

Cut the battery ground wire somewhere in the middle. Slide a piece of heat shrink tubing on each of the ground wires. Solder one ground wire to one of the pins and the other ground wire to the other pin. Make sure that they do not touch each other or the solder touches the metal body.

Verify that that are not connected using a multimeter. Slide the tubing over the soldered connections and shrink it. Add a bit of electrical tape to any part that may fail due to bending fatigue.

Step 3: Verify the battery works

At this point, the battery can be plugged into the CPX. If all went well, the switch should be able to turn on and off the CPX.

Step 4: Mount the battery

Put a bit of adhesive hook and loop tape on the back side of the battery and on the tie core. This will keep it in place if the tie is not manhandled too much.

Step 6: Setting Up the Circuit Playground Express

I won't go into detail about how to setup the CPX. Adafruit does that and then some. I will provide a few tips for issues that I encountered quite often.

CPX Freezes

Probably due to run time memory issues, the CPX would freeze quite often. The quick fix is to erase and re-flash. Search for "Old Way" in these instructions. Basically, it is a couple of button presses, a drag and drop to erase, and then a drag and drop to re-flash.

Warning: This erases everything. All code on the CPX will be lost.

Saving Changes to CPX Can Cause Issues

I discovered that sometimes after saving a file onto the CPX the python runtime would be in a bad state. The fix was restart the python runtime by pressing the reset button. Press it only once. Pressing it twice will start the re-flash process.

Saving Directly Onto CPX Is Risky

Because of the possibility that the CPX must be re-flashed, one runs the risk of loosing all of their code. After having lost my code twice, I came up with a simple workflow. I would save my code to the local hard disk. When it was ready to be tested on the CPX, I would simply copy it by running a simple deploy script.

Step 7: Coding the Circuit Playground Express

At this point, the CPX and NeoPixels are pretty much complete. No other mechanical or electrical work needs to be done with them. The rest is all software.

The code can be found at my github account. The core python code should work without any changes for all operating systems. Do not install the external Adafruit CircuitPython libraries. They are not used.

Here is a high level summary of what is going on in the code.

What Input Does What?

  • Button A: Cycles through the LED animations
  • Button B: Cycles through the songs
  • Capacitive Touch Pad A1: Changes the colors for the LED animations
  • Capacitive Touch Pad A6: Changes the speed of the LED animations

3 Animations Exist But Only 2 Are In Effect

code.py
import pixelsoff
#import vumeter
import stairs
import twinkle
...
led_animations = [
    pixelsoff.PixelsOff(pixels),
#    vumeter.VuMeter(pixels, 100, 400)
    stairs.Stairs(pixels),
    twinkle.Twinkle(pixels)
]

I ported the Ampli-Tie VU meter style code. It uses the CPX microphone to pick up sound and light up the NeoPixels based on sound amplitude. However, I wanted more animations. Due to runtime memory constraints I had to choose which animations I wanted. So by default the other two, Stairs and Twinkle, will run without having to make code changes. To run the VU meter animation, one or both of the other animations have to be commented out and VU meter uncommented.

Music Manager and Off-Line Encoding

frosty_the_snowman.py
import musical_notes as mn

# Frosty the Snowman
# Walter E. Rollins
song = [
    (mn.G4, mn.HLF),
    (mn.E4, mn.DTQ),
    (mn.F4, mn.ETH),
    (mn.G4, mn.QTR),
    (mn.C5, mn.HLF),
...

convert_to_binary.py
songs = [
    (jingle_bells.song, "jingle_bells.bin"),
    (frosty_the_snowman.song, "frosty_the_snowman.bin")
]

for song in songs:
    data=song[0]
    file=song[1]
    with open(file, "wb") as bin_file:
        for entry in data:
            print("writing: " + str(entry))
            note=entry[0]
            dur=entry[1]
            bin_file.write(struct.pack("<HH", note, dur))

I wanted holiday music. The CPX supports both WAV and tones. WAV files turned out to be too big in terms of file size and runtime memory. Using python data structures to hold tones and their duration also turned out to use too much runtime memory. So I modified the Holi-Tie code to read a compressed binary file which contained only the necessary song data in a compressed binary format. I wrote a script which reads a song held in a python data structure and writes it out to the binary format. Having the song encoded as binary data in a file makes the song both small and dynamic. Once the song is done playing, the memory is released.

It is trivial to add more songs. For details, see the README.md in songs.

Button A Animates NeoPixels, B Plays Music, But Not Simultaneously

code.py
def button_a_pressed():
    if music.is_playing(): # Stop music if playing
        music.stop()
    next_led_animation()

def button_b_pressed():
    if active_led_animation != 0: # Run no-op animation
        next_led_animation(0)
    if music.is_playing(): # Toggle music on or off
        music.stop()
    else:
        music.play()

Even with the more memory efficient music management system, I was not able to hold in runtime memory 2 animations, while playing 1 of them and also play a song all at the same time. Because I already opted not to have VU meter in runtime memory at all, I didn't want to reduce the number of animations down to just 1. So I wrote the code so that either the animation is playing or the music is playing but not both. Another option was to reduce the number of NeoPixels but that would loose some of the animation coolness.

Python Code Funkiness

Although I am a veteran software developer, I had never written Python. After I got the hang of it and stared applying good coding practices such as encapsulation and modularization, I quickly discovered I was using too much runtime memory. So there is a fair bit of non-DRY code. I also had to use some MicroPython techniques such as const() to further reduce run time memory issues.

Compiled Modules

compile
#!/bin/bash
compiler=~/development/circuitpython/mpy-cross-3.x-windows.exe

cd songs
python3 ./convert_to_binary.py
cd ..

for f in *.py; do
    if [[ $f != code.py ]]; then
	echo "compiling: $f"
	$compiler $f
    fi
done

Early in the project I followed Adafruit's advice and stored all of the Adafruit CircuitPython libraries on flash. This, however, left little room for my project. To be able to get my code onto the CPX, I started compiling the modules and placing them onto the MCU. It turns out that the Holi-Tie doesn't need any of the external libraries. The existing libraries in the UF2 were sufficient for this project. Running *.mpy files is a bit more effecient so I kept the process of deploying the compiled modules.

As evident in the compile script above, I am working on a Windows machine but using Unix utilities such as bash and python3. I use Cygwin to accomplish this. This script can easily be translated to DOS batch and a Windows native Python3 implementation.

Step 8: Buttoning Up the Tie

The final step is to put the tie core back into place, reassemble the tie, and sew it back up. Be sure to be able to make the CPX accessible. You will need it when replacing the battery or making code changes.

Holiday Decor

Participated in the
Holiday Decor