Skip to content

Instantly share code, notes, and snippets.

@dgrnbrg
Created April 24, 2023 12:02
Show Gist options
  • Save dgrnbrg/1f0e1e7d3b37c00e8edd985110deb989 to your computer and use it in GitHub Desktop.
Save dgrnbrg/1f0e1e7d3b37c00e8edd985110deb989 to your computer and use it in GitHub Desktop.
#######
####### In your python env, make sure you've installed pyartnet (`pip install pyartnet`)
#######
####### To run, you do: `python3 artnet.py` or `python3 artnet.py 2`
####### The numeric argument is the index of the pixel's color channel that we're animating
#######
####### This does a chaser effect up & down a 288 pixel strand on each port.
#######
####### You can run with an environment variable to change the universe. I run 12 copies in 12 terminals,
####### because the python I wrote isn't fast enough to run single-threaded, but even an older multicore
####### laptop can run 12 copies: e.g. `START_UNIVERSE=25 python artnet.py 3`
#######
import asyncio
import logging
from pyartnet import SacnNode, ArtNetNode
import sys
import os
import math
#######
####### IP Address
#######
IP_ADDR = '192.168.20.119'
#######
####### Mode should be `sacn` or `artnet` only
#######
THE_MODE = 'artnet'
#######
####### You want this 3 for RGB or 4 for RGBW pixels
#######
NUM_CHANNELS_PER_LED = 4
#######
####### This is how many pixels there are per led strand connector
#######
NUM_PIXEL_PER_STRAND = 288
#######
####### This is how many strands there are per dx connector
#######
STRANDS_PER_CONNECTOR = 4
#######
####### This is how many connectors are in use
#######
NUM_CONNECTORS = 1
#######
####### Uncomment the line below to see packets' bytes as they hit the wire
#######
#logging.basicConfig(level=logging.DEBUG)
async def main():
if len(sys.argv) >= 2:
i = int(sys.argv[1])
else:
i = 0
if i < 0 or i > NUM_CHANNELS_PER_LED:
raise ValueError(f"Arg should in 0-{NUM_CHANNELS_PER_LED}, the color index")
#x = int(sys.argv[2])
# This sets the max brightness we'll send out
x = 255
# Run this code in your async function
if THE_MODE == 'sacn':
node = SacnNode(IP_ADDR, 5568, max_fps=30)
elif THE_MODE == 'artnet':
node = ArtNetNode(IP_ADDR, 6454, max_fps=30)
else:
raise ValueError(f"Mode should only be sacn or artnet")
node.set_output_correction(None)
if os.getenv("START_UNIVERSE") is not None:
next_universe = int(os.getenv("START_UNIVERSE"))
else:
next_universe = 1
strands = []
for i_connector in range(NUM_CONNECTORS):
for i_strand in range(STRANDS_PER_CONNECTOR):
universe = node.add_universe(next_universe)
print(f"starting universe {next_universe} for strand {i_strand} on connector {i_connector}")
next_universe += 1
next_pos_in_universe = 1
channels = []
for i_pixel in range(NUM_PIXEL_PER_STRAND):
c = universe.add_channel(start = next_pos_in_universe, width=NUM_CHANNELS_PER_LED)
#print(f"universe={next_universe-1} start={next_pos_in_universe} width={NUM_CHANNELS_PER_LED}")
channels.append(c)
next_pos_in_universe += NUM_CHANNELS_PER_LED
if next_pos_in_universe + (NUM_CHANNELS_PER_LED-1) > 512:
print(f"filled universe {next_universe-1} because next_pos is {next_pos_in_universe}")
next_pos_in_universe = 1
universe = node.add_universe(next_universe)
next_universe += 1
print(f"used up to position {next_pos_in_universe} on {next_universe-1}")
strands.append(channels)
t = 0.9999999
p = 0
spread = 10
falloff = 2
dp = 0.5
dt = -0.001
while True:
val = [0] * NUM_CHANNELS_PER_LED
for channels in strands:
for idx,c in enumerate(channels):
if idx != p:
dist = spread / math.fabs(idx - p)**falloff
else:
dist = 1.0
if dist > 1.0:
dist = 1.0
elif dist < 0.0:
dist = 0.0
val[i] = int(x * dist)
c.set_values(val)
t += dt
if t > 1 or t < 0.2: # brightness between 100% and 20%
dt = -dt
t += dt
p += dp
if p > NUM_PIXEL_PER_STRAND or p < 0: # brightness between 100% and 20%
dp = -dp
p += dp
# GRBW
#print(f"value is {int(x*t)}")
await asyncio.sleep(0.002)
await asyncio.sleep(0.2)
asyncio.run(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment