LED-Streifen per Internet und Raspberry Pi steuern

LED-Streifen per Internet und Raspberry Pi steuern

Bereits die Tage hatte ich einen kleinen Artikel ( https://staticfloat.de/raspberry-pi/ws2812b-led-streifen-mit-einem-raspberry-pi-steuern/ ) dazu verfasst, wie wir an einem Raspberry Pi Zero einen WS2812B LED-Streifen zum leuchten bekommen. Natürlich mit samt Steuerung der einzelnen LEDs. Irgendwie kam mir dann die Idee, dass wir das Ganze doch auch ganz einfach per Internet steuern könnten.

Einfach am Handy oder PC eine bestimmte Internetadresse eingegeben und per Knopfdruck die Farben oder das Muster verändern … klickt doch toll oder?

Es gibt natürlich bereits diverse Anleitungen und fertige Software im Internet zum Download. Warum dann also dieser Artikel?
Ich bin ehrlich gesagt immer nicht so der riesige Fan von fertiger Software. Irgendwie ist es zwar sehr einfach, aber man schränkt sich auch unheimlich ein und ist auf Funktionen und Funktionsweisen angewiesen, die diese Software bietet. Außerdem kann man neben der Individualisierung am Ende noch sagen: “Hey, das habe ich gemacht” :P

Des weiteren wollen wir vielleicht doch einmal lernen wie dieser Software funktioniert und sie nicht nur einfach stupide benutzen. Aus diesem Grund verfasse ich jetzt diesen Artikel und hoffe ihr habt Spaß, bekommt eine Anwendung, die auf euch zugeschnitten ist und lernt dabei etwas.

Grundlage WS2812B – LED-Streifen

Als Grundlage für diesen Artikel setze ich voraus, dass ihr einen LED-Streifen besitzt, der WS2812B Controller besitzt, denn nur diese können wir mit Vorlage des vorigen Artikels steuern.
Oh und da wäre natürlich noch der Artikel ( https://staticfloat.de/raspberry-pi/ws2812b-led-streifen-mit-einem-raspberry-pi-steuern/ ) an sich. Bitte lest ihn euch durch und befolgt die Schritte. Hat alles geklappt, dann geht es hier weiter.

Funktionsweise

Wir haben vor einen LED Streifen per Internet zu steuern, also was benötigen wir? Natürlich einen Webserver, welchen wir auf einem beliebigen Gerät aufrufen können und dieser dann im Idealfall die LEDs steuert. In der Realität stellt einen Webserver, der auf dem Linux System sudo Befehle (Das Steuern der LEDs benötigt Sudo-Rechte) ausführen kann allerdings ein Sicherheitsproblem da. Aus diesem Grund werden wir über den Webserver lediglich eine Oberfläche anbieten, die dann eine bestimmte Datei verändern wird. Ein weiteres Skript, welches unabhängig vom Webserver und mit Sudo-Rechten läuft, wird wiederum diese Text Datei auslesen und den Inhalt entsprechend in Veränderungen des LED-Streifens umsetzen.

Klingt einleuchtend oder?
Wir werden das aber alles gleich noch einmal im Detail durchspielen.

Webserver

Als erstes müssen wir natürlich auf unserem raspberry Pei einen Web Server einrichten. Das einfachste wäre in diesem Fall einen Apache Server aufzusetzen und die Programmiersprache PHP einzubinden. PHP dient in diesem Falle dann zur Manipulation der angesprochenen Textdatei und der Apache Server dient zur Auslieferung der Seite.

Bitte führt also auf dem Pi aus:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install apache2 php7.0 libapache2-mod-php7.0
sudo service apache2 start

Damit haben wir jetzt bereits unseren Web Server aufgesetzt und könnten auf die Webseite unseres Raspberry Pi zugreifen. Dazu könnt ihr über den Befehl “ifconfig” die IP des Pi herausfinden und auf einem beliebigen anderen Gerät die Seite mittels der IP als Internetadresse anschauen. Wenn ihr direkt auf eurem Raspberry Pi arbeitet, dann könnt ihr im Browser auch “localhost” als Internetadresse eingeben.

Übrigens: Wer ein Android Handy besitzt, dem empfehle ich die App PingTool aus dem Playstore, um die IP der im Netzwerk befindlichen Geräte herauszufinden.

https://play.google.com/store/apps/details?id=ua.com.streamsoft.pingtools

Was wir jetzt vorliegen haben ist natürlich nur eine nackte Webseite ohne jegliche Funktionen. Aus diesem Grund müssen wir dem Webserver noch Logik verpassen. Was wir jetzt noch auf unserem Webserver machen wollen ist:

  • Anzeige von Knöpfen, die verschiedene Funktionen repräsentieren.
  • Jeder Funktion ist eine Nummer zugeordnet.
  • Beim Klick auf einen Knopf, die entsprechende Nummer in einer Textdatei speichern.

Alle weiteren Funktionen wird dann unser zusätzliches Skript übernehmen, welches im Hintergrund mit sudo rechten läuft und beim Start des Raspberry Pi gestartet wird.

Bitte führt nun folgenden Befehl aus:

cd /var/www/html
wget https://staticfloat.de/content/led-server.zip
unzip led-server.zip
sudo chmod 777 led-server/

Was haben wir jetzt eigentlich gemacht? Wir haben einen Web Server aufgesetzt, PHP installiert und mit den letzten drei Befehlen noch die entsprechende Logik zu unserem Webserver hinzugefügt. Die Logik ist relativ einfach gehalten und ich werde sie gleich noch einmal im Detail erklären.

Aber vorerst: Eure Webseite, zum Steuern des LED-Streifens ist nun aufrufbar über die Adresse “[IP des Pi]/led-server” oder direkt auf dem Pi über “localhost/led-server“.

Erklärung der Serverlogik

Das soeben heruntergeladene und entpackte PHP-Skript besteht aus zwei Teilen. Der erste Teil ist umgeben von den Tags “”. Dieser Teil regelt das Schreiben der aktuell gewünschten Funktion in eine Textdatei. Der zweite Teil (der nachfolgende Code) besteht aus der eigentlichen Anzeige der Knöpfe, beim Aufruf der Webseite.

Erster Teil

Hier wird über den Code “isset($_GET[‘function’])” geprüft, ob sich in der URL ein Part befindet, welcher in etwa so aussieht “?function=XXX”. Wenn dem so ist, dann wird der Inhalt dieses Parameters, im Beispiel das “XXX”, in die entsprechende Textdatei geschrieben.
Mehr passiert hier eigentlich nicht wirklich. Einfach oder?

Zweiter Teil

Ich möchte ehrlich sein. Wenn ihr diesen zweiten Part verstehen wollt, dann schaut euch am besten ein HTML Tutorial an. Alles andere würde hier den Rahmen sprechen. Wichtig ist eigentlich nur zu erwähnen, dass wenn ihr neue Funktionen hinzufügen wollt ihr folgenden Code repetitiv immer wieder hinzufügen könnt. Ändert dabei nur immer das “XX” und das “YY”. Achtet auch darauf, dass das später noch kommende Python-Skript auch was mit dem Befehl “XX” anfangen kann. :P

<input type="hidden" name="PHPSESSID" value="4fkdetnjlog7qgsplar9upup3o">
 <input type="hidden" name="function" value="XX">
 <button type="submit">YY</button>

Das Python Skript

Dieses Skript passiert auf dem Beispielcode “strandtest.py” von Tony DiCola, statt aber wie in dem Beispiel iterativ über die Funktionen zu gehen und alle Funktionen einmal auszuführen lesen wir hier stattdessen die von dem Webserver geschriebener Text Datei aus und führen dementsprechend je nach den dort enthaltenen Befehlscode eine andere Funktion aus. Weiterhin habe ich die Anzahl der LEDs auf 60 erhöht.

Um unser Python-Skript zu erstellen führen wir folgende Befehle aus:

cd rpi_ws281x/python/examples
nano led-client.py

Und fügen anschließend den folgenden Inhalt ein. Speichern können wir das Skript über STRG + X und bestätigen mit Y und Enter.

#!/usr/bin/env python3
# NeoPixel library strandtest example
# Author: Tony DiCola (tony@tonydicola.com)
#
# Edited by: staticfloat.de
# Edit note: Extended the script by using an textfile to determine the current used function.
#
# Direct port of the Arduino NeoPixel library strandtest example. Showcases
# various animations on a strip of NeoPixels.

import time
from neopixel import *
import argparse

# LED strip configuration:
LED_COUNT = 60 # Number of LED pixels.
LED_PIN = 18 # GPIO pin connected to the pixels (18 uses PWM!).
#LED_PIN = 10 # GPIO pin connected to the pixels (10 uses SPI /dev/spidev0.0).
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
LED_BRIGHTNESS = 255 # Set to 0 for darkest and 255 for brightest
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



# Define functions which animate LEDs in various ways.
def colorWipe(strip, color, wait_ms=50):
 """Wipe color across display a pixel at a time."""
 for i in range(strip.numPixels()):
 strip.setPixelColor(i, color)
 strip.show()
 time.sleep(wait_ms/1000.0)

def theaterChase(strip, color, wait_ms=50, iterations=10):
 """Movie theater light style chaser animation."""
 for j in range(iterations):
 for q in range(3):
 for i in range(0, strip.numPixels(), 3):
 strip.setPixelColor(i+q, color)
 strip.show()
 time.sleep(wait_ms/1000.0)
 for i in range(0, strip.numPixels(), 3):
 strip.setPixelColor(i+q, 0)

def wheel(pos):
 """Generate rainbow colors across 0-255 positions."""
 if pos < 85:
 return Color(pos * 3, 255 - pos * 3, 0)
 elif pos < 170:
 pos -= 85
 return Color(255 - pos * 3, 0, pos * 3)
 else:
 pos -= 170
 return Color(0, pos * 3, 255 - pos * 3)

def rainbow(strip, wait_ms=20, iterations=1):
 """Draw rainbow that fades across all pixels at once."""
 for j in range(256*iterations):
 for i in range(strip.numPixels()):
 strip.setPixelColor(i, wheel((i+j) & 255))
 strip.show()
 time.sleep(wait_ms/1000.0)

def rainbowCycle(strip, wait_ms=20, iterations=5):
 """Draw rainbow that uniformly distributes itself across all pixels."""
 for j in range(256*iterations):
 for i in range(strip.numPixels()):
 strip.setPixelColor(i, wheel((int(i * 256 / strip.numPixels()) + j) & 255))
 strip.show()
 time.sleep(wait_ms/1000.0)

def theaterChaseRainbow(strip, wait_ms=50):
 """Rainbow movie theater light style chaser animation."""
 for j in range(256):
 for q in range(3):
 for i in range(0, strip.numPixels(), 3):
 strip.setPixelColor(i+q, wheel((i+j) % 255))
 strip.show()
 time.sleep(wait_ms/1000.0)
 for i in range(0, strip.numPixels(), 3):
 strip.setPixelColor(i+q, 0)

# Main program logic follows:
if __name__ == '__main__':
 # Process arguments
 parser = argparse.ArgumentParser()
 parser.add_argument('-c', '--clear', action='store_true', help='clear the display on exit')
 args = parser.parse_args()

 # Create NeoPixel object with appropriate configuration.
 strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL)
 # Intialize the library (must be called once before other functions).
 strip.begin()

 print ('Press Ctrl-C to quit.')
 if not args.clear:
 print('Use "-c" argument to clear LEDs on exit')

 try:

 while True:
	 f = open("/var/www/html/led-server/befehl.txt", "r")
	 befehl = ''.join(f.read().split('\n'))
 if befehl == "01":
 colorWipe(strip, Color(255, 0, 0)) # Red wipe
 colorWipe(strip, Color(0, 255, 0)) # Blue wipe
 colorWipe(strip, Color(0, 0, 255)) # Green wipe
 elif befehl == "02":
 theaterChase(strip, Color(127, 127, 127))
 theaterChase(strip, Color(127, 0, 0))
 theaterChase(strip, Color( 0, 0, 127))
 elif befehl == "03":
 rainbow(strip)
 elif befehl == "04":
 rainbowCycle(strip)
 elif befehl == "05":
 theaterChaseRainbow(strip)
 else:
 colorWipe(strip, Color(0,0,0), 10)

 except KeyboardInterrupt:
 if args.clear:
 colorWipe(strip, Color(0,0,0), 10)

Nun müssen wir schlussendlich noch unser Paten Skript beim Start des Raspberry Pi mit starten, so dass wir direkt nach dem Boot auf den Webserver gehen und den LED Streifen steuern können.

Hier zu müssen wir noch einmal folgende Befehle eingeben:

sudo nano /etc/rc.local

Und den folgenden Inhalt, über der Stelle “exit 0”, in die Datei einfügen:

sudo PYTHONPATH=".:build/lib.linux-armv7l-2.7" python /home/pi/rpi_ws281x/python/examples/led-client.py

Ich wünsche viel Spaß und einen guten Rutsch!

Marvin

Ich bin ein Mensch, der sich neben der Programmierung noch für tausend andere Dinge interessiert, die mal mehr und mal weniger verrückt sind. Vor allem aber bin ich Feuer und Flamme mit der Programmierung von eigenen kleinen Apps und Programmen, die mein Leben bereichern.

Hat dir dieser Artikel gefallen?

Kommentar hinzufügen

*Pflichtfeld

  1. Nico Boeck

    Hey, bei mir gibt es das Problem, dass der Wert innerhalb der befehlt.txt Datei nicht geändert wird bei einem click auf einen Button.
    Bitte um Hilfe
    danke

  2. Marvin

    Hallo Nico,
    das könnte tatsächlich an fehlenden Rechten deines Websitenutzers liegen. Versuche mal folgenden Befehl: "sudo chmod -v 777 /var/www/html/led-server/befehl.txt".
    Sollte das klappen wären entsprechende Rechte schuld. Ansonsten helfe ich dir gerne per Mail weiter und würde den Artikel dann im Anschluss überarbeiten.

    Gruß
    Marvin

  3. Simon

    Klasse TuT !
    Allerdings habe ich Probleme mit dem led-client-Script
    Bei mir kommt dann immer die Ausgabe:

    Pi@raspberrypi:~/rpi_ws281x/python/examples $ python led-client.py
    File "led-client.py", line 31
    strip.setPixelColor(i, color)
    ^
    IndentationError: expected an indented block

    Dass es mit Python(2) ausgeführt wird, ist richtig? Weil im Script ist Python3 angegeben?!
    #!/usr/bin/env python3


  4. Marvin

    Hallo Simon,

    aus der Fehlermeldung heraus würde ich vermuten, dass der Code nicht richtig eingerückt ist. Bitte achte darauf, dass die Einrückung exakt der aus dem Artikel entspricht. Ich habe zur Sicherheit noch einmal den richtig eingerückten Code mit in die oben verlinkten ZIP eingebunden.

    Gruß
    Marvin

  5. Nico

    Hi,

    Erstmal danke für das tolle Tutorial.
    Leider habe ich dasselbe Problem wie Simon.
    Ich kann das Skirpt auch nicht in dem verlinkten zip entdecken?

    Grüße Nico