Seite 1 von 1

Interrupt mit Bottle / LED Steuerung

Verfasst: Montag 8. Oktober 2018, 19:39
von Kalle322
Hallo Community,

ich möchte eine LED Stripes (WS2801) die an die IOs von einem Raspberry angeschlossen ist, per http aufrufe steuern. Dazu habe ich python und bottle installiert. Das schalten per Webaufruf funktioniert ohne Probleme, jedoch habe ich nun das Problem, dass der Aufruf erst komplett abgearbeitet werden muss bevor der nächster Aufruf abgearbeitet wird. Ich möchte jedoch direkt auf die Änderungen reagieren. Nun die Frage, ist es möglich interrupts in Verbindung mit bottle zu programmieren damit immer der letzte http Aufruf abgearbeitet wird?

hier der bisherige code:

Code: Alles auswählen

from bottle import route, run, template

# Simple demo of of the WS2801/SPI-like addressable RGB LED lights.
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 = 160

# Alternatively specify a hardware SPI connection on /dev/spidev0.0:
SPI_PORT   = 0
SPI_DEVICE = 0
pixels = Adafruit_WS2801.WS2801Pixels(PIXEL_COUNT, spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE), gpio=GPIO)

# Define the wheel function to interpolate between different hues.
def wheel(pos):
    if pos < 85:
        return Adafruit_WS2801.RGB_to_color(pos * 3, 255 - pos * 3, 0)
    elif pos < 170:
        pos -= 85
        return Adafruit_WS2801.RGB_to_color(255 - pos * 3, 0, pos * 3)
    else:
        pos -= 170
        return Adafruit_WS2801.RGB_to_color(0, pos * 3, 255 - pos * 3)

def blink_color(pixels, blink_times=5, wait=0.5, speed=0.08, red=255, blue=0, green=0):
    for i in range(blink_times):
        # blink two times, then wait
        pixels.clear()
        for j in range(2):
            for k in range(pixels.count()):
                pixels.set_pixel(k, Adafruit_WS2801.RGB_to_color( red, blue, green ))
            pixels.show()
            time.sleep(speed)
            pixels.clear()
            pixels.show()
            time.sleep(speed)
        time.sleep(wait)

def rainbow_cycle(pixels, wait=0.005):
    for j in range(256): # one cycle of all 256 colors in the wheel
        for i in range(pixels.count()):
            pixels.set_pixel(i, wheel(((i * 256 // pixels.count()) + j) % 256) )
        pixels.show()
        if wait > 0:
            time.sleep(wait)

@route('/')
@route('/blink/<blink_times:int>/<wait:float>/<speed:float>/<red:int>/<blue:int>/<green:int>')
def blink(blink_times='2',wait='0.5',speed='0.08',red='255',blue='0',green='0'):
        pixels.clear()
        pixels.show()
        blink_color(pixels, blink_times = blink_times, wait = wait, speed = speed, red = red, blue = blue, green = green)

@route('/rainbow/<wait:float>')
def rainbow(wait='0.1'):
        pixels.clear()
        pixels.show()
        rainbow_cycle(pixels, wait = wait)

run(host='localhost', port=8080, debug=True)
Später möchte ich, dass die http Aufrufe in einer Schleife laufen und per nächster Http Aufruf beendet werden kann.

Ich freue mich über Anregungen und Lösungsansätze.

Vielen Dank und Viele Grüße

Re: Interrupt mit Bottle / LED Steuerung

Verfasst: Montag 8. Oktober 2018, 19:43
von __deets__
Bottle ist dafür nur bedingt geeignet. Denn bottle is synchron, ein request muss immer ein response erzeugen, und das ziemlich schnell. Sonst hängt dein Browser. Und im übrigen verlangt der das auch so, auch JavaScript kennt keine Threads.

Womit wir bei einer Lösung wären: verlager die LED Steuerung in einen Thread. Der bekommt dann von den HTTP-Aufrufen seine Anweisungen.

Alternativ kannst du tornado statt bottle verwenden. Und mit timer-basierten tasks arbeiten.

Re: Interrupt mit Bottle / LED Steuerung

Verfasst: Montag 8. Oktober 2018, 19:56
von Sirius3
@__deets__: das hat nichts mit bottle zu tun. Für bottle gibt es auch threaded dispatcher, z.B. mit unicorn, daneben gibts es auch noch gevent.

@Kalle322: Am besten benutzt Du einen Thread, den Du über eine Queue mit den Befehlen versorgst, die dann abgearbeitet werden sollen.

Re: Interrupt mit Bottle / LED Steuerung

Verfasst: Montag 8. Oktober 2018, 20:21
von __deets__
@Sirus3: natürlich hat das mit bottle zu tun, denn das geht anders als zB Tornado nicht davon aus, das man mit einem mainloop hantieren muss, in den man zeitgesteuerte Aufgaben hängen kann. Und daher dafür auch keine API mitbringt. Weswegen sich dein Vorschlag ja auch mit meinem deckt... 🙄

Das man mit gunicorn etc den Durchsatz steigern kann, ist bei einer Heimanwendung auf dem PI ja wohl eher irrelevant....

Re: Interrupt mit Bottle / LED Steuerung

Verfasst: Montag 8. Oktober 2018, 20:24
von Kalle322
Habe mich versucht in Threading einzulesen.

In der Theorie würde ich es so versuchen, dass ich die Funktionen der LEDs in eine Dauerschleife packe. In der Dauerschleife baue ich ein Switch/Case Konstrukt ein welches per globale Variablen gesteuert wird. Mit den Http Aufrufe würde ich dann die Globalen Variablen ändern.

Könnte es so funktionieren oder habt ihr eine bessere Idee?

Re: Interrupt mit Bottle / LED Steuerung

Verfasst: Montag 8. Oktober 2018, 20:39
von __deets__
Das geht, ja. Eine queue wie von Sirius3 vorgeschlagen ist eine Idee, weil man damit sowohl Thread sicher arbeitet, als auch per timeout auf dem get-call gleich die Timer-Frequenz bestimmen kann.

Re: Interrupt mit Bottle / LED Steuerung

Verfasst: Dienstag 9. Oktober 2018, 16:20
von Kalle322
Könnte mir Jemand hierfür ein Beispiel zeigen, damit ich meinen Code eventuell daran anpassen könnte?

Wäre demjenigen sehr sehr dankbar.

Viele Grüße

Re: Interrupt mit Bottle / LED Steuerung

Verfasst: Freitag 12. Oktober 2018, 08:25
von sls
@Kalle322: Hast du es zwischenzeitlich schon versucht? Klingt nach keiner zu komplexen Sache, den Thread startest du in einer main()-Funktion, wo du auch dein Queue-Objekt instanziierst. Damit die Queue befüllt wird, wirst du eine Schleife benötigen.

Re: Interrupt mit Bottle / LED Steuerung

Verfasst: Freitag 12. Oktober 2018, 09:11
von snafu
@Kalle322:
Du musst dir dafür im Code merken, ob aktuell eine Anfrage verarbeitet wird (Blinken / Rainbow). Diese muss bei einer neuen Anfrage abgebrochen werden, damit sofort die nächste Verarbeitung starten kann. Das ist doch, was du willst, oder? Man regelt das über Threads und ein Event, welches beim Eintreffen einer neuen Anfrage gesetzt werden sollte. Dies musst du jeweils in die beiden Schleifen einbauen und zu Beginn eines Durchlaufs den Status des besagten Events abfragen (d.h. ob abgebrochen werden soll). Lies dich hierzu am Besten erstmal ins Thema Threading ein. Dafür gibt es viele Tutorials.