Skript dauerhaft ausführen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Pascal09
User
Beiträge: 20
Registriert: Donnerstag 4. Januar 2018, 19:04

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)
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@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.
Pascal09
User
Beiträge: 20
Registriert: Donnerstag 4. Januar 2018, 19:04

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?
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nein, man muss einen dauerhaft laufenden Interpreter herbeiführen. Zb durch

Code: Alles auswählen

while True:
      time.sleep(1.0)
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@__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()
Pascal09
User
Beiträge: 20
Registriert: Donnerstag 4. Januar 2018, 19:04

ok das hätte ich ja im Leben nicht so hinbekommen :shock: danke schonmal werde es morgen testen
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

@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.
Pascal09
User
Beiträge: 20
Registriert: Donnerstag 4. Januar 2018, 19:04

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...
Pascal09
User
Beiträge: 20
Registriert: Donnerstag 4. Januar 2018, 19:04

Ist es vielleicht möglich das gpio.add_event_detect nur ausgeführt wenn der Pegel sich länger als 10ms geändert hat?
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

Hast du mal die Dokumentation zu add_event_detect durchgelesen? Das beantwortet die Frage.
Pascal09
User
Beiträge: 20
Registriert: Donnerstag 4. Januar 2018, 19:04

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.
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

Zeig mir doch mal welche Dokumentation zu add_event_detect du gelesen hast.
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

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.
Pascal09
User
Beiträge: 20
Registriert: Donnerstag 4. Januar 2018, 19:04

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?
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

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.
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

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.
Pascal09
User
Beiträge: 20
Registriert: Donnerstag 4. Januar 2018, 19:04

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?
Pascal09
User
Beiträge: 20
Registriert: Donnerstag 4. Januar 2018, 19:04

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.
__deets__
User
Beiträge: 14541
Registriert: Mittwoch 14. Oktober 2015, 14:29

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.
Antworten