Seite 1 von 2

Skript dauerhaft ausführen

Verfasst: Donnerstag 4. Januar 2018, 19:12
von Pascal09
Hallo
ich bin noch recht neu beim programmieren mit python..

Also ich habe jetzt ein Skript geschrieben und wenn ich es in Python2 über Run Module (F5) starte läuft es wie es soll, heißt die event detect werden immer erkannt.

Wenn ich aber über den LX Terminal das Skript starte wird es zwar ausgeführt aber anscheinend nur einmal und beendet sich dann wieder?

Ich will das Programm dauerhaft im Hintergrund ausführen.

Code: Alles auswählen

#!/usr/bin/env python

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
import time

import soco
import sys
from soco.discovery import by_name

Arbeitszimmer = by_name("Arbeitszimmer")
Wohnzimmer = by_name("Wohnzimmer")
Bad = by_name("Bad")
Kueche = by_name("Kueche")

GPIO.setup(22, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(23, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(24, GPIO.IN, pull_up_down = GPIO.PUD_UP)

def SchalterArbeitszimmer(channel):
    status_Arbeitszimmer = Arbeitszimmer.get_current_transport_info()
    status_Wohnzimmer = Wohnzimmer.get_current_transport_info()
    status_Bad = Bad.get_current_transport_info()
    status_Kueche = Kueche.get_current_transport_info()
    

    if GPIO.input(22) == GPIO.HIGH :
            Arbeitszimmer.unjoin()
            Arbeitszimmer.stop()

    elif status_Arbeitszimmer['current_transport_state'] == 'PLAYING' : status_Bad = Bad.get_current_transport_info()

    elif Bad.group.coordinator.player_name == "Bad" and status_Bad['current_transport_state'] == 'PLAYING' :
            Arbeitszimmer.join(Bad)
            Arbeitszimmer.volume = 15
            
    elif Kueche.group.coordinator.player_name == "Kueche" and status_Kueche['current_transport_state'] == 'PLAYING' :   
            Arbeitszimmer.join(Kueche)
            Arbeitszimmer.volume = 15

    elif Wohnzimmer.group.coordinator.player_name == "Wohnzimmer" and status_Wohnzimmer['current_transport_state'] == 'PLAYING' : 
            Arbeitszimmer.join(Wohnzimmer)
            Arbeitszimmer.volume = 15
            
    else:
            Arbeitszimmer.unjoin()
            Arbeitszimmer.play_uri('x-rincon-mp3radio://http://addrad.io/4WRMHX')
            Arbeitszimmer.volume = 15
            Arbeitszimmer.play()


GPIO.add_event_detect(22, GPIO.BOTH, callback = SchalterArbeitszimmer, bouncetime = 200)


def SchalterKueche(channel):
    status_Arbeitszimmer = Arbeitszimmer.get_current_transport_info()
    status_Wohnzimmer = Wohnzimmer.get_current_transport_info()
    status_Bad = Bad.get_current_transport_info()
    status_Kueche = Kueche.get_current_transport_info()
    

    if GPIO.input(23) == GPIO.HIGH :
            Kueche.unjoin()
            Kueche.stop()

    elif status_Kueche['current_transport_state'] == 'PLAYING' : status_Bad = Bad.get_current_transport_info()

    elif Bad.group.coordinator.player_name == "Bad" and status_Bad['current_transport_state'] == 'PLAYING' :
            Kueche.join(Bad)
            Kueche.volume = 15
            
    elif Arbeitszimmer.group.coordinator.player_name == "Arbeitszimmer" and status_Arbeitszimmer['current_transport_state'] == 'PLAYING' :   
            Kueche.join(Arbeitszimmer)
            Kueche.volume = 15

    elif Wohnzimmer.group.coordinator.player_name == "Wohnzimmer" and status_Wohnzimmer['current_transport_state'] == 'PLAYING' : 
            Kueche.join(Wohnzimmer)
            Kueche.volume = 15
            
    else:
            Kueche.unjoin()
            Kueche.play_uri('x-rincon-mp3radio://http://addrad.io/4WRMHX')
            Kueche.volume = 15
            Kueche.play()


GPIO.add_event_detect(23, GPIO.BOTH, callback = SchalterKueche, bouncetime = 200)


def SchalterBad(channel):
    status_Arbeitszimmer = Arbeitszimmer.get_current_transport_info()
    status_Wohnzimmer = Wohnzimmer.get_current_transport_info()
    status_Bad = Bad.get_current_transport_info()
    status_Kueche = Kueche.get_current_transport_info()
    

    if GPIO.input(24) == GPIO.HIGH :
            Bad.unjoin()
            Bad.stop()

    elif status_Bad['current_transport_state'] == 'PLAYING' : status_Bad = Bad.get_current_transport_info()

    elif Arbeitszimmer.group.coordinator.player_name == "Arbeitszimmer" and status_Arbeitszimmer['current_transport_state'] == 'PLAYING' :
            Bad.join(Arbeitszimmer)
            Bad.volume = 15
            
    elif Kueche.group.coordinator.player_name == "Kueche" and status_Kueche['current_transport_state'] == 'PLAYING' :   
            Bad.join(Kueche)
            Bad.volume = 15

    elif Wohnzimmer.group.coordinator.player_name == "Wohnzimmer" and status_Wohnzimmer['current_transport_state'] == 'PLAYING' : 
            Bad.join(Wohnzimmer)
            Bad.volume = 15
            
    else:
            Bad.unjoin()
            Bad.play_uri('x-rincon-mp3radio://http://addrad.io/4WRMHX')
            Bad.volume = 15
            Bad.play()


GPIO.add_event_detect(24, GPIO.BOTH, callback = SchalterBad, bouncetime = 200)

Re: Skript dauerhaft ausführen

Verfasst: Donnerstag 4. Januar 2018, 19:42
von Sirius3
@Pascal09: das Programm macht ja auch nichts; es fehlt das Hauptprogramm. In IDLE funktioniert das auch nur, weil die interaktive Konsole das Hauptprogramm ist; wobei funktioniert wohl zu weit geht, das tut halt irgendwas. Interruptgetrieben Programme korrekt zu schreiben ist schwierig. Das einfachste ist, über Queues zu kommunizieren. Die Interrupt-Funktion steckt etwas in die Queue, das Hauptprogramm holt es sich und verarbeitet es. Fang am besten mit print-Ausgaben, bis Du dieses Grundgerüst zusammengeschrieben hast.

Re: Skript dauerhaft ausführen

Verfasst: Donnerstag 4. Januar 2018, 19:51
von Pascal09
also es soll ja auch nur was passieren wenn die GPIOs geschaltet werden und das geht im mom ja auch. Müsste man nicht einfach diese Schalterabfrage so machen das er das immer abfragt?

Re: Skript dauerhaft ausführen

Verfasst: Donnerstag 4. Januar 2018, 21:15
von __deets__
Nein, man muss einen dauerhaft laufenden Interpreter herbeiführen. Zb durch

Code: Alles auswählen

while True:
      time.sleep(1.0)

Re: Skript dauerhaft ausführen

Verfasst: Donnerstag 4. Januar 2018, 21:54
von Sirius3
@__deets__: genau das ist das Problem. Weil es so viel Schrott im Internet zu GPIO gibt, und jeder von jedem kopiert, und jeder denkt, es funktioniert ja. Und dann kommen noch so tolle Hilfen; man kann ja auch mit Alufolie eine durchgebrannte Sicherung reparieren.

Code: Alles auswählen

#!/usr/bin/env python
from functools import partial
import RPi.GPIO as gpio
import soco
from soco.discovery import by_name
from Queue import Queue

def event_detect(pin, queue):
    queue.put((pin, gpio.input(pin) == gpio.HIGH))

def setup(pins):
    gpio.setmode(gpio.BCM)
    gpio.setup(pins, gpio.IN, pull_up_down=gpio.PUD_UP)
    processing_queue = Queue()
    for pin in pins:
        gpio.add_event_detect(pin, gpio.BOTH, bouncetime=200,
            callback=partial(event_detect, queue=processing_queue))
    return processing_queue

def process(rooms, pin, high):
    room = rooms[pin]
    if high:
        room.unjoin()
        room.stop()
    else:
        status = {
            pin: room.get_current_transport_info()
            for pin, room in rooms.items()
        }
        for pin2 in [24,23,22,0]:
            if status[pin2]['current_transport_state'] == 'PLAYING':
                if pin != pin2:
                    room.join(rooms[pin2])
                    room.volume = 15
                break
        else:
            room.unjoin()
            room.play_uri('x-rincon-mp3radio://http://addrad.io/4WRMHX')
            room.volume = 15
            room.play()

def main():
    processing_queue = setup([22, 23, 24])
    rooms = {
        22: by_name("Arbeitszimmer"),
        23: by_name("Kueche"),
        24: by_name("Bad"),
        0: by_name("Wohnzimmer"), # no pin?
    }

    while True:
        pin, high = processing_queue.get()
        process(rooms, pin, high)

if __name__ = '__main__':
    main()

Re: Skript dauerhaft ausführen

Verfasst: Donnerstag 4. Januar 2018, 22:07
von Pascal09
ok das hätte ich ja im Leben nicht so hinbekommen :shock: danke schonmal werde es morgen testen

Re: Skript dauerhaft ausführen

Verfasst: Donnerstag 4. Januar 2018, 23:42
von __deets__
@Sirius3 im Bezug auf Raspberry Pi Code und Leute die da Hilfe brauchen habe ich ehrlich gesagt jede Hoffnung fahren lassen. Glaubst du ernsthaft ich weiß nicht, wie das richtig gemacht wird? Nur hilf alles predigen nicht, wenn das Publikum kein Interesse daran hat, sich ernsthaft mit Python zu beschäftigen. Da soll der Temperatursensor mit dem Schlagbohrer verdrahtet werden, weil das für den Junggesellenabschied so geplant wurde - und das wars.

Du darfst gerne das Sprüchlein zu global, Einrückungen, PEP8 und Co loswerden. Ich bin persönlich dafür. Aber ich suche mir meine Kämpfe da aus. YMMV.

Re: Skript dauerhaft ausführen

Verfasst: Freitag 5. Januar 2018, 20:52
von Pascal09
Eine andere Frage hab ich noch.. vielleicht könnt ihr mir da auch weiterhelfen

Also es läuft jetzt alles soweit nur wenn ich in einem Raum den Lichtschalter betätige bekommen auch andere Räume das Signal.
Ich hab gelesen das man das mit einem Kondensator beheben kann. Allerdings bin ich mir nicht sicher wo der eingebaut werden müsste.

Also hier nochmal kurz der Fehler:

Arbeitszimmer Licht an = Music an

Küche Licht an = Music an

Arbeitszimmer Music über App ausgeschaltet / Licht bleibt an

Wenn ich jetzt im Bad oder Küche schalte bekommt der pin vom Arbeitszimmer auch ein Signal und geht an.

Der Fehler kommt nur wenn das Licht an ist und die Music per App ausgeschaltet wurde.

Hab schon versucht anstatt pullup mit einem pulldown aber da kommt der gleiche Fehler...

Re: Skript dauerhaft ausführen

Verfasst: Samstag 6. Januar 2018, 17:37
von Pascal09
Ist es vielleicht möglich das gpio.add_event_detect nur ausgeführt wenn der Pegel sich länger als 10ms geändert hat?

Re: Skript dauerhaft ausführen

Verfasst: Samstag 6. Januar 2018, 17:50
von __deets__
Hast du mal die Dokumentation zu add_event_detect durchgelesen? Das beantwortet die Frage.

Re: Skript dauerhaft ausführen

Verfasst: Samstag 6. Januar 2018, 19:07
von Pascal09
mh habe jetzt die ganze zeit gesucht aber irgendwie nicht die Lösung gefunden.. :K

Kannst du mir noch einen Tip geben wonach genau ich suchen muss.

Re: Skript dauerhaft ausführen

Verfasst: Samstag 6. Januar 2018, 19:09
von __deets__
Zeig mir doch mal welche Dokumentation zu add_event_detect du gelesen hast.

Re: Skript dauerhaft ausführen

Verfasst: Samstag 6. Januar 2018, 19:13
von Pascal09

Re: Skript dauerhaft ausführen

Verfasst: Samstag 6. Januar 2018, 19:17
von __deets__
Na da steht doch etwas im Zusammenhang mit Millisekunden. bouncetime. Die steht bei dir auf 200ms. Damit kann fuer 200ms nach einem Ereignis keines mehr ausgeloest werden, um "prellen" zu verhindern. Das *kann* ein Grund sein. Wenn du allerdings auch mit einzelnen Signalen die ausserhalb dieses 200ms Fensters kommen Probleme hast, dann denke ich hast du eher ein elektrisches Problem, das die Signale verschliffen sind, und erst eine kapazitive Last heben muessen. Da wuerden ggf. Treiber-Bausteine helfen.

Re: Skript dauerhaft ausführen

Verfasst: Samstag 6. Januar 2018, 19:20
von Pascal09
Ja das mit der Bouncetime weiß ich aber die zählt ja erst nach dem Ereignis..
Aber es wäre schön wenn man es machen könnte das die Flankenerkennung nur funktioniert wenn die Flanke dauerhaft geändert ist.
Kurze Impulse sollen irgnoriert werden.

Es ist ja im moment so das diese kurzen Impulse von anderen Schaltern die Flanke auslösen.

Was meinst du mit Treiber Bausteinen?

Re: Skript dauerhaft ausführen

Verfasst: Samstag 6. Januar 2018, 19:40
von __deets__
Wenn du kurze Impulse ignorieren willst, musst du die filtern. Da geht kein weg dran vorbei. Ich habe deine Frage diesbezueglich uebrigens missverstanden, ich dachte, das ist ein Problem fuer dich, und nicht ein gewuenschtes verhalten, das 10ms-Impulse ignoriert werden.

Natuerlich laesst sich das problemlos auch programmieren, allerdings kommen wir dann in die Wunderwelt der timer-programmierung, und da greifen die hier so salopp vorgestellten ansaetze nicht mehr.

Was stattdessen hilft ist entweder ein RC-Glied zu verbauen (ich bin da kein Experte, aber damit bekommt man ja einen Bandpass, und den kannst du so auslegen, das er eben Frequenzen nur unter zB 50 Hz durchlaesst).

Oder du versuchst mal das hier: https://gpiozero.readthedocs.io/en/stab ... nputdevice

gpiozero ist eh viel besser als das leider oft verwante RPI.GPIO.

Re: Skript dauerhaft ausführen

Verfasst: Samstag 6. Januar 2018, 19:47
von __deets__
Noch ein kleiner Nachtrag: wenn du damit klarkommst, dass du sowohl die steigende als auch die fallende Flanke beruecksichtigen kannst, dann ist das Problem milde einfacher. Dann kannst du dir bei steigender Flanke einfach einen Timestamp merken, und bei fallender die verflossene Zeit messen. Eine Verarbeitung findet dann nur statt, wenn genug Zeit vergangen ist.

Das heisst aber, das zB eine Klingel erst beim loslassen schellt.

Re: Skript dauerhaft ausführen

Verfasst: Samstag 6. Januar 2018, 20:12
von Pascal09
Also ich verwende ja eh Schalter und keine Taster.
Desswegen soll ja nur was ausgeführt werden wenn der Status zB eine gewisse Zeit besteht.

Kannst du mir vielleicht ein Beispiel geben wie ich das (11.8. SmoothedInputDevice) einsetzen muss?

Re: Skript dauerhaft ausführen

Verfasst: Samstag 6. Januar 2018, 20:43
von Pascal09
Oder ich hab grad noch eine andere Idee.
Wie kann ich abfragen ob eine steigende oder fallende Flanke erkannt wurde?


http://www.netzmafia.de/skripten/hardwa ... O_int.html
Im letzten Fall muss dann innerhalb der Callback-Funktion der entsprechende Port ausgelesen werden, um festzustellen, ob der Auslöser eine steigende Flanke (Port-Wert "1") oder eine fallende war (Port-Wert "0").


Leider steht da nicht wie man es auslesen kann.

Re: Skript dauerhaft ausführen

Verfasst: Samstag 6. Januar 2018, 22:11
von __deets__
Das Beispiel von Sirius3 zeigt das doch. Er steckt den Pegel doch in die Queue. Und auch gpiozero kann das natuerlich.

Nachtrag: und in deinem eigenen Link wird das doch auch gezeigt.