Project Idea, could use help - 1m LED independent modules that sync up

Hey there friends! I have had an idea for a while now, and I started to get components and try things out, but I would love to get some thoughts from you all.

First a few things about the “project”. I am getting into helping a small crew that throws renegade events in remote or unpowered areas. We typically have 1-2 hours to set up and tear down, and each location is very different.

I want to build some 1m LED strip modules, where each module is self powered via a battery and has it’s own controller. These can then be placed all around the venue for the event. Ideally each module is pretty resilient and water resistant.

In an ideal world, I’d love to be able to sync patterns across any number of modules that connect, but also have them run in an “independent” mode.

My current thinking is that I use diffuser channels with an APA102 1m strip of 60leds. These are connected to a PB on one end, and a usb battery on the other. I would need to 3d print the PB enclosure and same with the battery connection.

The hardware part I’m less concerned about, but I’ve been noodling on how I could do a distributed pattern across these using pixel blaze. My first thought is that I could create a pixel mapping that just has all of them in there, even though the blaze in each module only has 1 strip directly connected, but this will assume an order to the modules. It might not be a huge deal, but I like the idea of being able to move things around. The other thought I had was to just use fireblaze to sync patterns, but then it wouldn’t so much be a distributed pattern as it would be synced same patterns. I know it’s on the roadmap to have a single audio source to share as an input on multiple PB’s, but that would also be perfect for this project.

I’m imagining 10-12 modules that I can put up wherever for events in vertical and horizontal orientations.

I appreciate any thoughts, ideas, or questions for this. Will try to update as I build out a few modules and test out different options!

Have you seen some of the diffused tube enclosures from JAD? If you contact them they might be able to customize the chips used inside. Granted you don’t get your batteries and controllers directly in the enclosure.

https://a.aliexpress.com/_mOWVbr4

For a suggested mapping scheme, consider mapping each controller as a separate column in a top-to-bottom non-zigzag matrix. I would think this would produce decent cohesion + difference on most 2D patterns. You could hang these in a circle around your venue or hang them as-mapped off a suspended line to render similar to many recent nightclub installs; the coordinated-but-offset output probably would look good as an abstract thing even if you tiled them in a triangular grid or connected them as a septagram, etc.

For now you’d need firestorm somewhere to orchestrate pattern changes.

If you’re going to have a laptop or whatnot to run Firestorm, you can use the pixelblaze-client library to broadcast data from one sensor expansion board to the other Pixelblazes with this little program:

broadcastSensorData.py
#!/usr/bin/env python3

# Import standard library modules.
import argparse
from datetime import datetime

# Import third-party packages.
from pixelblaze import *

# ------------------------------------------------

def timeInMilliseconds():
    td = datetime.now()
    return (td.microsecond + (td.second + td.day * 86400) * 10**6) // 10**3

# Here's where the action starts.
if __name__ == "__main__":

    # Parse command line.
    parser = argparse.ArgumentParser()
    parser.add_argument("--fromIpAddress", required=True, help="The IP address of the Pixelblaze to copy expansion board variables FROM")
    parser.add_argument("--toIpAddress", required=True, help="The IP address (or comma-separated list of IP addresses) of the Pixelblaze(s) to copy expansion board variables TO")
    parser.add_argument("--verbose", action='store_true', help="Display debugging output")
    args = parser.parse_args()

    print(args.toIpAddress)

    # Connect to the Pixelblazes.
    print(f"Connecting to source Pixelblaze @ {args.fromIpAddress}...")
    with Pixelblaze(args.fromIpAddress) as src:
        dests = []
        for destIP in args.toIpAddress.split(','):
            print(f"Connecting to destination Pixelblaze @ {destIP}...")
            dests.append(Pixelblaze(destIP))

        print("Mirroring expander board variables; press [Ctrl]-[c] to quit...")
        numSamples = 0
        lastVars = {}
        lastTime = timeInMilliseconds()
        extra = ''
        while True:
            try:
                # Get the exported variables from the source Pixelblaze.
                vars = src.getActiveVariables()
                numSamples += 1
                # Remove any variables not related to the expansion board.
                for key in list(vars.keys()):
                    if not key in ['light', 'accelerometer', 'analogInputs', 'frequencyData', 'energyAverage', 'maxFrequency', 'maxFrequencyMagnitude']:
                        del vars[key]
                if args.verbose: extra = f": {vars}"
                print(f"Received frame {numSamples}{extra}\r", end='')
                if len(vars) > 0 and lastVars != vars:
                        print(f"Sending  frame {numSamples}\r", end='')
                        for dest in dests:
                            dest.setActiveVariables(vars)
                # Back off for a while, since the sensor board only updates every 25 millliseconds.
                thisTime = timeInMilliseconds()
                deltaTime = 25 - (thisTime - lastTime)
                lastTime = thisTime
                if deltaTime > 0: time.sleep(deltaTime / 1000)
            except KeyboardInterrupt:
                print('')
                break

Oh, those diffused tubes are pretty cool. 24v is annoying to do with smaller batteries though. Even 12v is not ideal given the form factor for any battery that can supply that.

Love the mapping idea, will try that out with my three test strips.

Ahh… this is too perfect. Thank you! Will mess with this once I get firestorm up and running!

So in poking around on ali express, I found these battery powered light tubes.

I wish I could pick up one of these to take apart and see if it’s possible to stick a mini pixel blaze in there and highjack the led data connection and route that to the PB.

This already has the battery, charging port, and tube set up.

These look super interesting. I’m going to pick one up and see what’s going on inside. A project I work on has some Nanlites, and even thought they’re not addressable, they’re pretty fun for ambiance / photography. If these are addressable, even better.

I messaged the seller on ali to see what kind of leds they use in there. Will let you know what I find out! You have to buy them in 5 packs (probably since it’s free shipping). If I get a pack, would be happy to ship one to you.

Been playing around with this, and not quite sure I am getting it right.

If I understand this correctly, what I would want is lets say I have 10 of these, each with 60 pixels.

I would have each PB set to a 10x60 matrix in the mapper (not zigzag), but then in the render function I would have to do a translation.

If you are module 5, that means your pixels 0-59 are actually 250-299 in the pattern. How do I have the render method ignore all of the other index draws, and then shift the pattern at pixels 250-299 to 0-59 for that strip?

@hex337, actually what I like is using ghost pixels in the map (beyond pixelCount) to position the real pixels differently in an overall (0-1,0-1) space.

The advantage is that all 2D patterns don’t need code added at all (no 2D space transforms added to each device).

Here’s an example for two vertical bars of 60 LEDs. Each has the number of pixels set to 60 in Settings. Any additional “ghost” points added in the mapper will affect the overall positioning of the first 60 pixels in the global 0-1 X and Y space, but they will not be passed into render()/render2D().

Book1 2022-12-21 09-27-45

Book1 2022-12-21 09-30-34

What this does is it keeps each’s bar’s pixel indices in the code to be 0-59. Therefore, 1D patterns will duplicate themselves perfectly across all the bars with no code modifications. If you want slight offsets between bars for 1D patterns, that’s easy enough to do by adding a 2D renderer to those 1D patterns. Consider:

export function render(index) {
  # (some 1D renderer)
}

export function render2D(index, x, y) {
  render(index + floor(x * pixelCount))
}

Or, for the many 1D patterns that use the index / pixelCount fraction as their spacial dimension:

export function render(index, frac) {
  h = frac
  hsv(h, 1, 1)
}

export function render2D(index, x, y) {
  render(index, index/pixelCount + x)
}

Oh… that would be way easier. So in the map, I just have the normal map for 60 pixels that go from the given x position based on which bar it is. Then after those are mapped, I add 1 or 2 extra pixels at the two ends to “normalize” the other 60. Will play around with that.

This makes syncing stuff with firestorm way easier too :slight_smile:

1 Like

sometimes y’all read my mind. i was looking into getting those light bars too to hang in our camp’s social space for the upcoming burn (yes i’m already working on stuff for 2023).

the only difference is that we wouldn’t be doing battery powered because it needs to run all night every night for a week. so i’m looking at building out a way to send power over CAT6 cables which should be easier to wire up. the open question i had in my head was whether to do one PB per light bar (which could get expensive), or have a PB controlling all the light bars. i’m kind of thinking to settle in a halfway solution where 3 or 4 light bars would be chained to a single PB.

I’d be looking to cover a space of 45’ x 45’ with what i’d assume to be about 15-20 of those light bars.

1 Like

I just got my 3d printer set up, and will start messing with enclosures for the board and battery, but I might try and make it modular so that you can just have a usb plug going in without needing a battery.

and just to satisfy the “maker” part of my brain, i’m going to try to see if i can build a light bar using common parts for more cheaply than the ones on aliexpress since i want to have at least 15 of them and the cost savings could add up.

building them without controllers inside would keep costs down. i see in another thread links to an external site where a guy created a custom PCB that would allow for using cat6 to send power and data over longer distances.

might be cool to repurpose a powered ppoe switch to become a general use expansion board… PB to the uplink port, then plug in the LEDs anyone thought about that or looked into it?

one issue with using a standard ppoe switch is that they provide power at 48V and my google searching doesn’t really turn up a lot of options for building a compact 48V → 5V step down.