Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapt for ws2801 lights #123

Closed
benwicks opened this issue Feb 10, 2018 · 10 comments
Closed

Adapt for ws2801 lights #123

benwicks opened this issue Feb 10, 2018 · 10 comments

Comments

@benwicks
Copy link

benwicks commented Feb 10, 2018

Hi, I'm interested in using your project with my ws2801 LED strand. Can you help me understand what modifications will be necessary to work with those lights? Thank you.

@kevkid
Copy link

kevkid commented Mar 1, 2018

I second this!

@kevkid
Copy link

kevkid commented Mar 2, 2018

@benwicks Okay... So I just adapted it for the ws2801 led strip. It is a bit quick and dirty but here yah go!
Step 0: Follow instructions and install prerequisites from here:

sudo apt-get update
sudo apt-get install python-pip -y
sudo pip install adafruit-ws2801

Step 1 edit your config to the number of lights that you want. You do not need frequency and whatnot. The library will handle that for us.
Step 2 edit your led.py to this:

from __future__ import print_function
from __future__ import division

import platform
import numpy as np
import config

# ESP8266 uses WiFi communication
if config.DEVICE == 'esp8266':
    import socket
    _sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Raspberry Pi controls the LED strip directly
elif config.DEVICE == 'pi':
    import time
    import RPi.GPIO as GPIO
 
    # Import the WS2801 module.
    import Adafruit_WS2801
    import Adafruit_GPIO.SPI as SPI
 
 
    # Configure the count of pixels:
    PIXEL_COUNT = config.N_PIXELS
 
# Alternatively specify a hardware SPI connection on /dev/spidev0.0:
    SPI_PORT   = 0
    SPI_DEVICE = 0
    strip=Adafruit_WS2801.WS2801Pixels(PIXEL_COUNT, spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE), gpio=GPIO)
 

    strip.clear()
    strip.show()
elif config.DEVICE == 'blinkstick':
    from blinkstick import blinkstick
    import signal
    import sys
    #Will turn all leds off when invoked.
    def signal_handler(signal, frame):
        all_off = [0]*(config.N_PIXELS*3)
        stick.set_led_data(0, all_off)
        sys.exit(0)

    stick = blinkstick.find_first()
    # Create a listener that turns the leds off when the program terminates
    signal.signal(signal.SIGTERM, signal_handler)
    signal.signal(signal.SIGINT, signal_handler)

_gamma = np.load(config.GAMMA_TABLE_PATH)
"""Gamma lookup table used for nonlinear brightness correction"""

_prev_pixels = np.tile(253, (3, config.N_PIXELS))
"""Pixel values that were most recently displayed on the LED strip"""

pixels = np.tile(255, (3, config.N_PIXELS))
"""Pixel values for the LED strip"""

_is_python_2 = int(platform.python_version_tuple()[0]) == 2

def _update_esp8266():
    """Sends UDP packets to ESP8266 to update LED strip values

    The ESP8266 will receive and decode the packets to determine what values
    to display on the LED strip. The communication protocol supports LED strips
    with a maximum of 256 LEDs.

    The packet encoding scheme is:
        |i|r|g|b|
    where
        i (0 to 255): Index of LED to change (zero-based)
        r (0 to 255): Red value of LED
        g (0 to 255): Green value of LED
        b (0 to 255): Blue value of LED
    """
    global pixels, _prev_pixels
    # Truncate values and cast to integer
    pixels = np.clip(pixels, 0, 255).astype(int)
    # Optionally apply gamma correc tio
    p = _gamma[pixels] if config.SOFTWARE_GAMMA_CORRECTION else np.copy(pixels)
    MAX_PIXELS_PER_PACKET = 126
    # Pixel indices
    idx = range(pixels.shape[1])
    idx = [i for i in idx if not np.array_equal(p[:, i], _prev_pixels[:, i])]
    n_packets = len(idx) // MAX_PIXELS_PER_PACKET + 1
    idx = np.array_split(idx, n_packets)
    for packet_indices in idx:
        m = '' if _is_python_2 else []
        for i in packet_indices:
            if _is_python_2:
                m += chr(i) + chr(p[0][i]) + chr(p[1][i]) + chr(p[2][i])
            else:
                m.append(i)  # Index of pixel to change
                m.append(p[0][i])  # Pixel red value
                m.append(p[1][i])  # Pixel green value
                m.append(p[2][i])  # Pixel blue value
        m = m if _is_python_2 else bytes(m)
        _sock.sendto(m, (config.UDP_IP, config.UDP_PORT))
    _prev_pixels = np.copy(p)


def _update_pi():
    """Writes new LED values to the Raspberry Pi's LED strip

    Raspberry Pi uses the rpi_ws281x to control the LED strip directly.
    This function updates the LED strip with new values.
    """
    global pixels, _prev_pixels
    # Truncate values and cast to integer
    pixels = np.clip(pixels, 0, 255).astype(int)
    # Optional gamma correction
    p = _gamma[pixels] if config.SOFTWARE_GAMMA_CORRECTION else np.copy(pixels)
    # Encode 24-bit LED values in 32 bit integers
    r = p[0][:].astype(int) #np.left_shift(p[0][:].astype(int), 8)
    g = p[1][:].astype(int) #np.left_shift(p[1][:].astype(int), 16)
    b = p[2][:].astype(int) #p[2][:].astype(int)
    # Update the pixels
    for i in range(config.N_PIXELS):
        # Ignore pixels if they haven't changed (saves bandwidth)
        if np.array_equal(p[:, i], _prev_pixels[:, i]):
            continue
        strip.set_pixel(i, Adafruit_WS2801.RGB_to_color( r[i], g[i], b[i] ))
    _prev_pixels = np.copy(p)
    strip.show()

def _update_blinkstick():
    """Writes new LED values to the Blinkstick.
        This function updates the LED strip with new values.
    """
    global pixels
    
    # Truncate values and cast to integer
    pixels = np.clip(pixels, 0, 255).astype(int)
    # Optional gamma correction
    p = _gamma[pixels] if config.SOFTWARE_GAMMA_CORRECTION else np.copy(pixels)
    # Read the rgb values
    r = p[0][:].astype(int)
    g = p[1][:].astype(int)
    b = p[2][:].astype(int)

    #create array in which we will store the led states
    newstrip = [None]*(config.N_PIXELS*3)

    for i in range(config.N_PIXELS):
        # blinkstick uses GRB format
        newstrip[i*3] = g[i]
        newstrip[i*3+1] = r[i]
        newstrip[i*3+2] = b[i]
    #send the data to the blinkstick
    stick.set_led_data(0, newstrip)


def update():
    """Updates the LED strip values"""
    if config.DEVICE == 'esp8266':
        _update_esp8266()
    elif config.DEVICE == 'pi':
        _update_pi()
    elif config.DEVICE == 'blinkstick':
        _update_blinkstick()
    else:
        raise ValueError('Invalid device selected')


# Execute this file to run a LED strand test
# If everything is working, you should see a red, green, and blue pixel scroll
# across the LED strip continously
if __name__ == '__main__':
    import time
    # Turn all pixels off
    pixels *= 0
    pixels[0, 0] = 255  # Set 1st pixel red
    pixels[1, 1] = 255  # Set 2nd pixel green
    pixels[2, 2] = 255  # Set 3rd pixel blue
    print('Starting LED strand test')
    while True:
        pixels = np.roll(pixels, 1, axis=1)
        update()
        time.sleep(.1)

if you get that buffer overflow follow this edit:

fa492bb

@kevkid
Copy link

kevkid commented Mar 4, 2018

@benwicks After some work I was able to set up a nice server to control the lights with this visualizer included. If you want to take a look at it check here

@benwicks
Copy link
Author

benwicks commented Mar 5, 2018

Looks great @kevkid! I don't have a microphone yet so am waiting a little longer to try this. I will keep a record of your work to try once I acquire a microphone. Thanks!

@benwicks benwicks closed this as completed Mar 5, 2018
@kevkid
Copy link

kevkid commented Mar 5, 2018

@benwicks Awesome! Good luck setting up your lights! If you have any questions about my project let me know!

@gaijinsr
Copy link

I am also using a strip of WS2801 LEDs, they are connected to an ESP8266 running ESPlightNode, and I have patched led.py to send Artnet output (see issue 134). Works like a charm.

@benwicks
Copy link
Author

@kevkid I had time to set up your project today. My strand has 25 lights and the basics are working ok. But, when I turn on the visualizer, I get this output and see no change on the lights. Do you think there might be an issue getting ahold of the microphone? Thanks for all the help so far!

ALSA lib pcm_dmix.c:1018:(snd_pcm_dmix_open) unable to open slave
ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear
ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe
ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side
ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.hdmi
ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.hdmi
ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.modem
ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.modem
ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline
ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline
ALSA lib pcm_dmix.c:957:(snd_pcm_dmix_open) The dmix plugin supports only playback stream
ALSA lib pcm_dmix.c:1018:(snd_pcm_dmix_open) unable to open slave
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
FPS 48 / 60
FPS 20 / 60
FPS 14 / 60
FPS 12 / 60
FPS 12 / 60
FPS 12 / 60
FPS 12 / 60
FPS 13 / 60
...

@kevkid
Copy link

kevkid commented Mar 29, 2018

@benwicks there may be several things going on. Try this check list to make sure that everything is the way it should.

  • Did you set the correct number of LEDs? There are 2 sections in my project one in light_control.py and one in led.py

  • Is your microphone working? From my understanding you do have to edit some settings in linux to get it to make the microphone as the default device.

  • Did you run everything as sudo?

@benwicks
Copy link
Author

benwicks commented Apr 2, 2018

Thanks. I did notice I didn't have the right number of LEDs specified in the config.py file. Now, I'm not sure how to proceed with making sure the microphone is working. Do you have a link to walk through how to configure my microphone as the default device in linux?

@kevkid
Copy link

kevkid commented Apr 2, 2018

@benwicks I used the default configuration from this github. Follow what was written here for the Pi and it should work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants