Raspberrypi LED-Daemon

2025 - Jul 13

Driving Neopixel/WS2812-Leds on a raspberrypi turns out to be a root only job since you need to talk to the bus-System directly. Since I did'nt want to run the rest of my project as root I decided to implement a LED-Daemon that can be accessed via Socket.

In my setup I use pin 18 as control pin for the ws281x-LEDs. As result the daemon listens on port 9999 for incomming commands:

color R G B set all LEDs to color. Color values each 0..255, seperated by space
ledcolor N R G B set color value of a specific LED. N==position of the LED, R G B: colorvalues 0..255
off turn all leds off

In future releases there might be additional commands but for in a first iteration this very simple server is perfectly adequate.

Code of the server:

import socket
import threading
import time
from rpi_ws281x import PixelStrip, Color

# LED strip configuration:
LED_COUNT = 12        # Number of LED pixels.
LED_PIN = 18          # GPIO pin connected to the pixels (18 is PWM).
LED_FREQ_HZ = 800000  # LED signal frequency in hertz (usually 800khz)
LED_DMA = 10          # DMA channel to use for generating the signal (try 10)
LED_INVERT = False    # True to invert the signal (when using NPN transistor level shift)
LED_CHANNEL = 0       # set to '1' for GPIOs 13, 19, 41, 45 or 53

# Create an instance of the PixelStrip class
strip = PixelStrip(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, 255, LED_CHANNEL)
strip.begin()

def set_color(color):
    """Set the color of the entire LED strip."""
    for i in range(strip.numPixels()):
        strip.setPixelColor(i, color)
    strip.show()

def set_led(i, color):
    """Set the color of the entire LED strip."""
    print(f"Set Pixel {i}  to {color}")
    strip.setPixelColor(i, color)
    strip.show()

def handle_client_connection(client_socket):
    """Handle incoming client connections."""
    while True:
        request = client_socket.recv(1024).decode('utf-8')
        if not request:
            break
        
        if request.startswith("color "):
            _, r, g, b = request.split()
            color = Color(int(r), int(g), int(b))  # RGB to WS2812 format
            set_color(color)
            client_socket.send(b'Color set\n')
        elif request.startswith("ledcolor "):
            _, n, r, g, b = request.split()
            color = Color(int(r), int(g), int(b))  # RGB to WS2812 format
            set_led(int(n), color)
            client_socket.send(b'Single Color set for pixel \n')
        elif request == "off":
            set_color(Color(0, 0, 0))
            client_socket.send(b'LEDs turned off\n')
        else:
            client_socket.send(b'Unknown command\n')

    client_socket.close()

def start_server():
    """Start the socket server to listen for commands."""
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind(('127.0.0.1', 9999))  # Listen on port 9999
    server.listen(5)
    print("Listening for connections on port 9999...")
    
    while True:
        client_socket, addr = server.accept()
        print(f"Accepted connection from {addr}")
        client_handler = threading.Thread(target=handle_client_connection, args=(client_socket,))
        client_handler.start()

if __name__ == "__main__":
    try:
        start_server()
    except KeyboardInterrupt:
        set_color(Color(0, 0, 0))  # Turn off LEDs on 

On the client side we can now send commands to control the LEDs. E.g. color 255 0 0 would light up all LEDs of the LED-strip red.

A minimal client example would look like:

import socket
import time

def send_command(command):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect(('127.0.0.1', 9999))  # Connect to localhost
        s.sendall(command.encode('utf-8'))
        response = s.recv(1024)
        print(response.decode('utf-8'))

# Example usage
send_command("color 255 0 0")  # Set to red
time.sleep(2)
send_command("off")             # Turn off