subprocess.check_output (mit cut und grep)

  • Hallo zusammen,

    ich hab seit Tagen ein kleines Problem mit meinem Python Skript. Nachdem ich nun so ziemlich jedes Forum fast jeden Beitrag abgeklappert habe, wende ich mich an euch :D

    Ich hab ein Skript welches in der root crontab bei jedem reboot startet.

    Code
    @reboot /bin/sleep 30 && /usr/bin/python /usr/bin/bewegungsmelder.py &

    Ich habe aber in meinem Skript mehrere Schleifen und kann den Fehler auf ziemlich genau eine Zeile eingrenzen. Als nicht gelernter Programmierer, kenn ich natürlich nicht die verscheidenen Module von Python, aber ich vermute, dass das Problem hier liegt. Ich komm darauf, weil wenn das Skript im Hintergrund (mit-)startet, genau den while-Teil "falsch" macht..
    [code=php]
    #nach 2 Geräten suchen mit insgesamt maximal 5 Durchgängen
    while (k <= 5) and (device1 == 0) and (device2 == 0):
    print "%s: Suche Gerät1 ..." % datetime.datetime.now()
    response1 = subprocess.check_output('/usr/bin/nmap -F **IP-ADRESSE** -Pn -sF | grep "host" | cut -d"(" -f2 | cut -d")" -f1 | cut -d" " -f1', shell=True)
    device1 = int(response1)
    if device1==1:
    print "%s: Gerät 1: GEFUNDEN (%s. Versuch)" % (datetime.datetime.now(), k)
    else:
    print "%s: Gerät 1: keine Antwort (%s. Versuch)" % (datetime.datetime.now(), k)
    print "%s: Suche Gerät 2 ..." % datetime.datetime.now()
    response2 = subprocess.check_output('/usr/bin/nmap -F **IP-ADRESSE** -Pn -sF | grep "host" | cut -d"(" -f2 | cut -d")" -f1 | cut -d" " -f1', shell=True)
    device2 = int(response2)
    if device2==1:
    print "%s: Gerät 2: GEFUNDEN (%s. Versuch)" % (datetime.datetime.now(), k)
    else:
    print "%s: Gerät 2: keine Antwort (%s. Versuch)" % (datetime.datetime.now(), k)
    #zähler
    k = k + 1

    #ausführen, wenn keines der beiden Geräte erreichbar ist
    if device1==0 and device2==0:
    print "%s: KEIN GERÄT GEFUNDEN! Starte jetzt den TelegramBot" % datetime.datetime.now()
    def handle(msg):
    if 'text' in msg and msg['text'] == '/start':
    with open('/usr/bin/id.txt', 'w') as f:
    f.write(str(msg['chat']['id']))
    bot = telepot.Bot('******')
    bot.message_loop(handle)
    print "%s: TelegramBot: Suche Empfänger-ID aus Liste ..." % datetime.datetime.now()
    with open('/usr/bin/id.txt', 'r') as idfile:
    chat_id=int(idfile.read())
    bot.sendMessage(chat_id, "\n========================\nACHTUNG!\nJemand ist zuhause!")
    print "%s: TelegramBot: Nachricht erfolgreich abgeschickt!" % datetime.datetime.now()
    time.sleep(1)
    print "%s: Warte 5 Minuten" % datetime.datetime.now()
    time.sleep(300)

    #wenn ein Gerät erreichbar ist
    else:
    print "%s: Kein Alarm! Mindestens ein Gerät wurde im Netzwerk gefunden" % datetime.datetime.now()
    print "%s: Warte 5 Minuten" % datetime.datetime.now()
    time.sleep(300)
    [/php]
    Was soll das Skript machen?
    Es soll max. 5x nach 2 Geräten im gleichen Netzwerk sind suchen. Sobald eines erreichbar ist, zum nächsten Abschnitt springen. Der wäre dann (wenn kein Gerät erreichbar ist) das Verschicken einer Nachricht über Telegram bzw. Telepot (fehlerfrei).

    Wie gesagt, ich bin kein Programmierer, aber ich schätze, dass es an diesen Zeilen liegt:
    [code=php]response1 = subprocess.check_output('/usr/bin/nmap -F **IP-ADRESSE** -Pn -sF | grep "host" | cut -d"(" -f2 | cut -d")" -f1 | cut -d" " -f1', shell=True)
    [...]
    response2 = subprocess.check_output('/usr/bin/nmap -F **IP-ADRESSE** -Pn -sF | grep "host" | cut -d"(" -f2 | cut -d")" -f1 | cut -d" " -f1', shell=True)
    [/php]
    "Von Hand" im Terminal eingegeben, ergibt das genau immer den Wert 0 oder 1 (je nach Erreichbarkeit).. :denker:

    Vielleicht könnt ihr mir dabei helfen und vielleicht den entscheidenden Tipp geben :helpnew:
    Entschuldigt auch die evtl. vorhandenen kleinen Fehler. Hatte nur mal etwas Java und alles andere ausm Netz und probieren, probieren, probieren

    Einmal editiert, zuletzt von nobody2311 (20. April 2017 um 08:48)

  • Wenn das Script nicht permanent läuft dann ist "&" am Ende der crontab-Zeile überflüssig.

    Für Python sind Einrückungen extrem wichtig. Soweit ich das sehe erhöht sich "k" nur an einer Stelle und das auch nur bei der Suche nach Gerät#2

    Zunächst würde ich für das Suchen nach einem Gerät eine Funktion definieren, damit sich nahezu gleicher Code nicht mehrfach wiederholt. Bei der Gerätesuche unterscheidet sich anscheint nur die IP, also übergibt man die IP der Funktion und gibt das Ergebnis zurück.

    Du scheinst auch "nmap" nur dazu zu verwenden eine IP im Netzwerk zu finden - Deine Zeile zielt auf die letzte Ausgabe von "nmap" ab => Nmap done: 1 IP address (1 host up) scanned in 3.63 seconds
    Problem: Bei meinen Tests kann es ziemlich lange dauern bis nmap beendet wird wenn ein Host nicht erreichbar ist.
    Aber was spricht gegen einen einfachen Ping? Das wäre nämlich nativ direkt mit Python möglich, ohne Shellbefehle - erstrebenswertes Ziel: So viel wie möglich in der selben Sprache machen, so gut es geht auf andere Sprachen oder externe Befehle verzichten.
    Ein Beispiel findest du hier: https://github.com/meigrafd/Sample-Code/blob/master/ping.py

    Es gibt aber auch ein Python Module für nmap: https://bitbucket.org/xael/python-nmap

    Code
    sudo apt-get install python-nmap

    Beispiel für dein Vorhaben:
    [code=php]
    import nmap
    from datetime import datetime

    def finde_geraet(IP='127.0.0.1', args='-F -Pn -sF', count=5):
    while count > 0:
    print "[%s] <%d> Suche Gerät: %s" % (datetime.now().strftime('%d.%m.%Y %H:%M:%S'), count, IP)
    res = None
    try: res = nm.scan(IP, arguments=args)
    except nmap.nmap.PortScannerError: pass
    if res:
    if nm[IP].state() == "up":
    return True
    count -= 1
    return False

    nm = nmap.PortScanner()

    success_1 = finde_geraet('8.8.8.8')
    success_2 = finde_geraet('10.8.0.20')
    if not success_1 and not success_2:
    print "[%s] KEIN GERÄT GEFUNDEN! Starte jetzt den TelegramBot" % datetime.now().strftime('%d.%m.%Y %H:%M:%S')
    [/php]


    PS: Da das Script via Crontab gestartet wird können keinerlei Ausgaben erfolgen bzw gesehen werden. Wenn, dann müsstest du die Ausgaben in eine Datei umleiten, was man auch mit Fehlern machen kann, oder das Module "logging" verwenden.
    Weiterführende Infos: FAQ => Nützliche Links / Linksammlung => crontab

  • Danke für eure schnelle Antwort :thumbs1:


    Soweit ich das sehe erhöht sich "k" nur an einer Stelle und das auch nur bei der Suche nach Gerät#2


    Huch, das hat sich wohl beim copy&paste verschoben. "k" sollte sich erst am Ende der while-Schleife um 1 erhöhen :blush: Habs im Beitrag ausgebessert


    Du scheinst auch "nmap" nur dazu zu verwenden eine IP im Netzwerk zu finden
    [..]
    Aber was spricht gegen einen einfachen Ping?


    Einen einfachen Ping, hatte ich am Anfang bereits versucht, aber kurioserweise wurde dann das Android-Gerät nicht gefunden. Im Netz fand ich dann diverse Berichte, wo anscheinend Android ab 6.x auf einen Ping nicht reagiert. Mit nmap kam das zwar auch mal vor, aber spätestens nach dem 2./3. Versuch, gab es dann eine positive Rückmeldung, daher die 5 Versuche.

    Danke für dein Beispiel-Code. Ich habs etwas angepasst und das Modul installiert und am Anfang hinzugefügt. Soweit kann ich alles nachvollziehen und (fast) jede Zeile verstehen. Die Funktion (nennt man den "def"-Teil so?!) liefert ein True oder ein False nachdem man es mit "success_x = finde_geraet('xxx.xxx.xxx.xxx')" aufgerufen hat. Startet bei 5 und zählt am Ende bis 0 runter.
    [code=php]
    def finde_geraet(IP='127.0.0.1', args='-F -Pn -sF', count=5):
    while count > 0:
    print "%s: Suche Gerät %s ..." % (datetime.datetime.now(), IP)
    res = None
    try: res = nm.scan(IP, arguments=args)
    except nmap.nmap.PortScannerError: pass
    if res:
    if nm[IP].state() == "up":
    return True
    count -= 1
    return False

    nm = nmap.PortScanner()

    success_1 = finde_geraet('**IP-ADRESSE1**')
    success_2 = finde_geraet('**IP-ADRESSE2**')
    if not success_1 and not success_2:
    [..]
    [/php]

    Leider bekomme ich beim ausführen im Terminal dann eine Fehlermeldung und kann damit aber irgendwie nichts anfangen. Scheint so, als wenn es ein Problem mit dem Ergebnis "up" gibt :s Habs auch mal mit "open" versucht, aber da neigt sich mein "halbwissen" dem Ende zu ;)
    (Das Gerät mit der **IP-ADRESSE2** war in dem Moment im gleichen Netzwerk)

    [code=php]2017-04-20 07:41:00.641399: Bewegung erkannt!
    2017-04-20 07:41:02.693227: Suche Gerät **IP-ADRESSE1** ...
    2017-04-20 07:41:15.792825: Suche Gerät **IP-ADRESSE2** ...
    Traceback (most recent call last):
    File "/usr/bin/bewegungsmelder.py", line 93, in <module>
    success_2 = finde_geraet('192.168.178.31')
    File "/usr/bin/bewegungsmelder.py", line 85, in finde_geraet
    if nm[IP].state() == "up":
    File "/usr/lib/python2.7/dist-packages/nmap/nmap.py", line 567, in __getitem__
    return self._scan_result['scan'][host]
    KeyError: '**IP-ADRESSE2**'
    [/php]


    Wenn das Skript permanent läuft m.E. ebenfalls.


    Habs entfernt ;)

    Einmal editiert, zuletzt von nobody2311 (20. April 2017 um 08:47)

  • Hallo zusammen,

    Wenn das Skript permanent läuft m.E. ebenfalls.

    Diese Frage lässt sich doch recht leicht klären.

    Wenn das aufgerufene Skript irgendwelche Informationen bereitstellt oder irgendwelche Fakten schafft, auf die nach diesem Skript gestartete Programme angewiesen sind oder warten sollen/müssen, dann ohne "&". Das hängt letztlich vom Kontext ab, unter dem der TE das Skript laufen lassen möchte. Das Skript selber hat eine zeitlich begrenzte Laufzeit.

    Wenn dass Programm einfach loslegen soll und andere Prozesse nicht behindern soll, dann mit "&". Wenn das Programm zeitlich unbegrenzt laufen soll, und ständig Daten für andere Prozesse liefert oder abholt, dann immer mit "&". Dass dieses Skript in einem solchen Kontext laufen können soll, gibt der Quell-Code so erst einmal nicht her.


    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

    Einmal editiert, zuletzt von Andreas (20. April 2017 um 08:48)

  • Ah okay, ja das lässt sich schnell beantworten. ;)

    Der Raspberry Pi dient zusammen mit einem Monitor und einem Spionspiegel als "SmartMirror". Das gesamte Skript steuern ein Relais, welches dann einen Monitor ein/ausschaltet, sobald jemand vor dem Bewegungsmelder ist. Der Rest vom Skript arbeitet fehlerfrei, deswegen hab ich nur den "relevanten" Teil kopiert, zumal die restlichen Zeilen auch nicht von mir sind.

    ..daher also dann mit "&"

  • Andreas: Nein das ist leider Quatsch. Programme die über crontab ausgeführt werden laufen automatisch im Hintergrund, daher bewirkt das einfache "&" über crontab nichts.
    Nur wenn man zB /etc/rc.local verwendet benötigt man ein "&" um den Befehl/Programm in den Hintergrund zu schicken und /etc/rc.local nicht zu blockieren, mit anderen Prozessen hat das nichts zu tun. Aber eigentlich auch völlig wurscht weil hier crontab zum Einsatz kommt also wieso darüber unterhalten? :-/


    nobody2311: Kannst du bitte die Fehlermeldung unverändert posten? Mit deinen LAN IP-Adressen können wir sowieso nichts anstellen, deshalb sind es ja LAN Adresse. 192.168.178.31 hast du zB vergessen durch **IP-ADRESSE2** zu ersetzen.

    Aber so ohne weiteres weiß ich jetzt nicht wieso die Fehlermeldung kommt. Dann versuchen wirs halt doch erst über den Weg aus Beitrag#1....

    Vielleicht beschreibst du noch mal das Problem aus Beitrag#1 genauer?
    Weil da schreibst du nur: while-Teil "falsch" macht
    Das ist aber ein bisschen mager ;)

  • Hallo Meigrafd,


    Andreas: Nein das ist leider Quatsch. Programme die über crontab ausgeführt werden laufen automatisch im Hintergrund, daher bewirkt das einfache "&" über crontab nichts.
    Nur wenn man zB /etc/rc.local verwendet benötigt man ein "&" um den Befehl/Programm in den Hintergrund zu schicken und /etc/rc.local nicht zu blockieren, mit anderen Prozessen hat das nichts zu tun. Aber eigentlich auch völlig wurscht weil hier crontab zum Einsatz kommt also wieso darüber unterhalten? :-/

    dass es hier um einen Crontab handelte ist mir nicht aufgefallen - trifft aber hier zu, nachdem ich hier nach Crontab gesucht habe.

    Für jeden anderen Fall gilt mein Beitrag allerdings uneingeschränkt - und in der Allgemeingültigkeit habe ich ihn auch verstanden. Denn man kann Skripte auch innerhalb von Programmen ausführen - nicht nur auf Basis von crontab, rc.local, bashrc, ...

    Diesen meinen Beitrag deshalb einfach so als Quatsch abzutun, schreibe ich Dir als unübertroffenem Selbstdarsteller zu - und dass es Dir immer nur daum geht, andere herunterzuziehen, damit Dein Licht über allem erstrahlen kann.

    Dies ist hoffentlich mein letzter Beitrag auf Angriffe deinerseits auf mich. Mir ist die Zeit zu schade. Mögen andere in die Bresche springen - oder es auch sein lassen. Ist mir mittlerweile auch egal, was Du hier verbreitest. Die Fakten sprechen eh für sich - und an denen kommst selbst Du nicht herum.


    Bist Du echt so jung und unerfahren, dass es Dir so schwerfällt, Dich einer Wortwahl zu befleißigen, die andere nicht verletzt? Die Welt drehte sich noch nie nur um Dich. Oder siehst Du das so? Deinem Verhalten nach zu urteilen schon, gelle?


    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

  • Du zitierst Teile von Beiträgen in denen "crontab" steht und schreibst direkt darunter "lässt sich recht leicht klären", meinst später aber "crontab" nicht gesehen zu haben?
    In einem anderen Thread unterstellst Du mir Haarspalterei, weil ich (und Tell) bei der blosen Erwähnung von "Grafik" nicht nur eine Bilddatei sehe - hier aber glaubst Du crontab ignorieren zu können um über andere Umstände zu philosophieren?
    Und nun meinst Du mich persönlich angreifen zu müssen nur weil ich "Nein das ist leider Quatsch" geschrieben habe?
    ... ah jetzt ja ...


  • Kannst du bitte die Fehlermeldung unverändert posten? Mit deinen LAN IP-Adressen können wir sowieso nichts anstellen, deshalb sind es ja LAN Adresse. 192.168.178.31 hast du zB vergessen durch **IP-ADRESSE2** zu ersetzen.


    Verdammt, erwischt :lol: Okay, dann unverändert ;) Hier einmal das gesamte Skript mit nmap als Modul (hab nur den Bot-Token entfernt ;) )
    [code=php]
    #!/usr/bin/python
    # -*- coding: utf-8 -*-

    import RPi.GPIO as GPIO
    import time
    import datetime
    import subprocess
    import telepot
    import nmap

    #Board Mode anstelle GPIO BCM Nummer
    GPIO.setmode(GPIO.BOARD)

    # GPIO 7 = Bewegungsmelder
    # GPIO 11 = Relais
    GPIO_PIR = 7
    GPIO_MON = 11

    print "Bewegungsmelder Test (CTRL-C zum Beenden)"
    print "========================================="

    # GPIO als "Input" festlegen
    GPIO.setup(GPIO_PIR,GPIO.IN)
    GPIO.setup(GPIO_MON,GPIO.OUT)

    try:

    while True :

    # Status von Sensor auslesen
    Current_State = GPIO.input(GPIO_PIR)
    time.sleep(0.2)

    # Wenn Bewegung, dann ...
    if Current_State==1 and Previous_State==0:

    print "%s: Bewegung erkannt!" % datetime.datetime.now()
    Previous_State=1
    GPIO.output(GPIO_MON, GPIO.LOW)
    time.sleep(1)
    GPIO.output(GPIO_MON, GPIO.HIGH)
    time.sleep(1)

    #if not response1 and not response2:
    def finde_geraet(IP='127.0.0.1', args='-F -Pn -sF', count=5):
    while count > 0:
    print "%s: Suche Gerät %s ..." % (datetime.datetime.now(), IP)
    res = None
    try: res = nm.scan(IP, arguments=args)
    except nmap.nmap.PortScannerError: pass
    if res:
    if nm[IP].state() == "open":
    return True
    count -= 1
    return False

    nm = nmap.PortScanner()

    success_1 = finde_geraet('192.168.178.20')
    success_2 = finde_geraet('192.168.178.31')
    if not success_1 and not success_2:
    print "%s: KEIN GERÄT GEFUNDEN! Starte jetzt den TelegramBot" % datetime.datetime.now()
    def handle(msg):
    if 'text' in msg and msg['text'] == '/start':
    with open('/usr/bin/bewegungsmelder_id.txt', 'w') as f:
    f.write(str(msg['chat']['id']))
    bot = telepot.Bot('*******')
    bot.message_loop(handle)
    print "%s: TelegramBot: Suche Empfänger-ID aus Liste ..." % datetime.datetime.now()
    with open('/usr/bin/bewegungsmelder_id.txt', 'r') as idfile:
    chat_id=int(idfile.read())
    bot.sendMessage(chat_id, "\n========================\nACHTUNG!\nJemand ist zuhause!")
    print "%s: TelegramBot: Nachricht erfolgreich abgeschickt!" % datetime.datetime.now()
    time.sleep(1)
    print "%s: Warte 6 Minuten" % datetime.datetime.now()
    time.sleep(360)

    else:
    print "%s: Kein Alarm! Mindestens ein Gerät wurde im Netzwerk gefunden" % datetime.datetime.now()
    print "%s: Warte 6 Minuten" % datetime.datetime.now()
    time.sleep(360)
        
    # Wenn keine Bewegung, dann ...
    elif Current_State==0 and Previous_State==1:

    print " %s: Fertig! Warte auf Bewegung..." % datetime.datetime.now()
    Previous_State=0
    GPIO.output(GPIO_MON, GPIO.LOW)
    time.sleep(1)
    GPIO.output(GPIO_MON, GPIO.HIGH)
    time.sleep(1)
      
    except KeyboardInterrupt:
    print " Exit"
    GPIO.cleanup()
    [/php]

    und die dazugehörige Fehlermeldung:
    [code=php]2017-04-20 07:41:00.641399: Bewegung erkannt!
    2017-04-20 07:41:02.693227: Suche Gerät 192.168.178.20 ...
    2017-04-20 07:41:15.792825: Suche Gerät 192.168.178.31 ...
    Traceback (most recent call last):
    File "/usr/bin/bewegungsmelder.py", line 93, in <module>
    success_2 = finde_geraet('192.168.178.31')
    File "/usr/bin/bewegungsmelder.py", line 85, in finde_geraet
    if nm[IP].state() == "up":
    File "/usr/lib/python2.7/dist-packages/nmap/nmap.py", line 567, in __getitem__
    return self._scan_result['scan'][host]
    KeyError: '192.168.178.31' [/php]


    Vielleicht beschreibst du noch mal das Problem aus Beitrag#1 genauer?
    Weil da schreibst du nur: while-Teil "falsch" macht
    Das ist aber ein bisschen mager ;)

    Stimmt, sorry, war schlecht formuliert. Also bei dem Skript aus Beitrag#1 wird der while-Teil übersprungen, d.h. egal ob eins der beiden Geräte im Netzwerk ist, wird die Nachricht direkt (über Telepot/Telegram) verschickt. Funktioniert aber "richtig", wenn sich keines der beiden Geräte im Netzwerk befindet.
    ..und hier das gesamte Skript ohne nmap Modul, aber mit dem ursprünglichen cut/grep und überspringen der while-Schleife:
    [code=php]
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    PATH=/usr/bin:/bin:/sbin

    import RPi.GPIO as GPIO
    import time
    import datetime
    import subprocess
    import telepot

    #Board Mode anstelle GPIO BCM Nummer
    GPIO.setmode(GPIO.BOARD)

    # GPIO 7 = Bewegungsmelder
    # GPIO 11 = Relais
    GPIO_PIR = 7
    GPIO_MON = 11

    print "Bewegungsmelder Test (CTRL-C zum Beenden)"
    print "========================================="

    # GPIO als "Input" festlegen
    GPIO.setup(GPIO_PIR,GPIO.IN)
    GPIO.setup(GPIO_MON,GPIO.OUT)

    k = int(1)
    response1 = 0
    response2 = 0
    device1 = 0
    device2 = 0
    Current_State = 0
    Previous_State = 0

    try:

    #print "%s: Sensor initialisieren ..." % datetime.datetime.now()

    # Warten bis Sensor sich meldet
    #while GPIO.input(GPIO_PIR)==1:
    #Current_State = 0
    #time.sleep(0.2)

    #print "%s: Fertig! Warte auf Bewegung..." % datetime.datetime.now()

    # Schleife bis CTRL+C
    while True :

    # Status von Sensor auslesen
    Current_State = GPIO.input(GPIO_PIR)
    time.sleep(0.2)

    # Wenn Bewegung, dann ...
    if Current_State==1 and Previous_State==0:

    print "%s: Bewegung erkannt!" % datetime.datetime.now()
    Previous_State=1
    GPIO.output(GPIO_MON, GPIO.LOW)
    time.sleep(1)
    GPIO.output(GPIO_MON, GPIO.HIGH)
    time.sleep(1)
    while (k <= 5) and (device1 == 0) and (device2 == 0):
    print "%s: Suche Gerät1 ..." % datetime.datetime.now()
    response1 = subprocess.check_output('/usr/bin/nmap -F 192.168.178.20 -Pn -sF | grep "host" | cut -d"(" -f2 | cut -d")" -f1 | cut -d" " -f1', shell=True)
    device1 = int(response1)
    if device1==1:
    print "%s: Gerät 1: GEFUNDEN (%s. Versuch)" % (datetime.datetime.now(), k)
    else:
    print "%s: Gerät 1: keine Antwort (%s. Versuch)" % (datetime.datetime.now(), k)
    print "%s: Suche Gerät 2 ..." % datetime.datetime.now()
    response2 = subprocess.check_output('/usr/bin/nmap -F 192.168.178.31 -Pn -sF | grep "host" | cut -d"(" -f2 | cut -d")" -f1 | cut -d" " -f1', shell=True)
    device2 = int(response2)
    if device2==1:
    print "%s: Gerät 2: GEFUNDEN (%s. Versuch)" % (datetime.datetime.now(), k)
    else:
    print "%s: Gerät 2: keine Antwort (%s. Versuch)" % (datetime.datetime.now(), k)
    #zähler
    k = k + 1

    if device1==0 and device2==0:
    print "%s: KEIN GERÄT GEFUNDEN! Starte jetzt den TelegramBot" % datetime.datetime.now()
    def handle(msg):
    if 'text' in msg and msg['text'] == '/start':
    with open('/usr/bin/bewegungsmelder_id.txt', 'w') as f:
    f.write(str(msg['chat']['id']))
    bot = telepot.Bot('******')
    bot.message_loop(handle)
    print "%s: TelegramBot: Suche Empfänger-ID aus Liste ..." % datetime.datetime.now()
    with open('/usr/bin/bewegungsmelder_id.txt', 'r') as idfile:
    chat_id=int(idfile.read())
    bot.sendMessage(chat_id, "\n========================\nACHTUNG!\nJemand ist zuhause!")
    print "%s: TelegramBot: Nachricht erfolgreich abgeschickt!" % datetime.datetime.now()
    time.sleep(1)
    print "%s: Warte 5 Minuten" % datetime.datetime.now()
    time.sleep(300)

    else:
    print "%s: Kein Alarm! Mindestens ein Gerät wurde im Netzwerk gefunden" % datetime.datetime.now()
    print "%s: Warte 5 Minuten" % datetime.datetime.now()
    time.sleep(300)
        
    # Wenn keine Bewegung, dann ...
    elif Current_State==0 and Previous_State==1:

    print " %s: Fertig! Warte auf Bewegung..." % datetime.datetime.now()
    Previous_State=0
    GPIO.output(GPIO_MON, GPIO.LOW)
    time.sleep(1)
    GPIO.output(GPIO_MON, GPIO.HIGH)
    time.sleep(1)
      
    except KeyboardInterrupt:
    print " Exit"
    GPIO.cleanup()
    [/php]

    Einmal editiert, zuletzt von nobody2311 (20. April 2017 um 11:31)

  • Zunächst solltest du dir einheitliche Einrückungen angewöhnen, nicht mal 2, mal 4, mal 8 sondern durchweg 4.
    In einer Schleife keine Funktion definieren, sondern ausserhalb.
    In /usr/bin/ keine Texdateien ablegen.


    Dann konzentrieren wir uns erst mal auf das Ursprüngliche Script und erstellen da ähnlich wie bei nmap eine Funktion zum abrufen deiner Geräte:

    Aber das kann nicht sein... In meinem LAN gibt es nur 192.168.0.x
    Insofern solltest du noch mal prüfen ob das wirklich fehlerfrei bei dir funktioniert.


    Dein Script angepasst: http://codepad.org/McoUbblF
    [code=php]
    #!/usr/bin/python
    # -*- coding: utf-8 -*-

    from RPi import GPIO
    import time
    import datetime
    import subprocess
    import telepot

    geraet_1 = '192.168.178.31'
    geraet_2 = '192.168.178.20'

    # GPIO 7 = Bewegungsmelder
    # GPIO 11 = Relais
    GPIO_PIR = 7
    GPIO_MON = 11


    #Board Mode anstelle GPIO BCM Nummer
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(GPIO_PIR, GPIO.IN)
    GPIO.setup(GPIO_MON, GPIO.OUT)


    def finde_geraet(IP='127.0.0.1', count=5):
    while count > 0:
    print "%s: <%d> Suche Gerät: %s" % (datetime.datetime.now(), count, IP)
    response = subprocess.check_output('/usr/bin/nmap -F -Pn -sF %s | grep "host up)"' % IP, shell=True)
    if response:
    return True
    count -= 1
    return False


    def handle(msg):
    if 'text' in msg and msg['text'] == '/start':
    with open('/tmp/bewegungsmelder_id.txt', 'w') as f:
    f.write(str(msg['chat']['id']))


    def printD(message):
    print "%s: %s" % (datetime.datetime.now(), message)


    Current_State = 0
    Previous_State = 0
    try:
    while True:
    Current_State = GPIO.input(GPIO_PIR)
    time.sleep(0.2)

    if Current_State==1 and Previous_State==0:
    printD("Bewegung erkannt!")
    Previous_State=1
    GPIO.output(GPIO_MON, GPIO.LOW)
    time.sleep(1)
    GPIO.output(GPIO_MON, GPIO.HIGH)
    time.sleep(1)

    printD("Suche Gerät1 ...")
    device1 = finde_geraet(geraet_1)
    if device1:
    printD("Gerät 1: GEFUNDEN")
    else:
    printD("Gerät 1: keine Antwort")

    printD("Suche Gerät2 ...")
    device2 = finde_geraet(geraet_2)
    if device2:
    printD("Gerät 2: GEFUNDEN")
    else:
    printD("Gerät 2: keine Antwort")

    if not device1 and not device2:
    printD("KEIN GERÄT GEFUNDEN! Starte den TelegramBot")

    bot = telepot.Bot('******')
    bot.message_loop(handle)
    printD("TelegramBot: Suche Empfänger-ID aus Liste ...")
    with open('/usr/bin/bewegungsmelder_id.txt', 'r') as idfile:
    chat_id=int(idfile.read())
    bot.sendMessage(chat_id, "\n========================\nACHTUNG!\nJemand ist zuhause!")
    printD("TelegramBot: Nachricht erfolgreich abgeschickt!")
    else:
    printD("Kein Alarm! Mindestens ein Gerät wurde im Netzwerk gefunden")

    printD("Warte 5 Minuten")
    time.sleep(300)

    elif Current_State==0 and Previous_State==1:

    printD("Fertig! Warte auf Bewegung...")
    Previous_State=0
    GPIO.output(GPIO_MON, GPIO.LOW)
    time.sleep(1)
    GPIO.output(GPIO_MON, GPIO.HIGH)
    time.sleep(1)

    except KeyboardInterrupt:
    print " Exit"
    GPIO.cleanup()
    [/php]

    Hab mir auch erlaubt für deine prints eine Funktion zu setzen, falls du später mal das Design ändern willst brauchst du das nur ein mal anpassen ;)


  • Zunächst solltest du dir einheitliche Einrückungen angewöhnen, nicht mal 2, mal 4, mal 8 sondern durchweg 4.
    In einer Schleife keine Funktion definieren, sondern ausserhalb.
    In /usr/bin/ keine Texdateien ablegen.


    Ah okay, dann werd ich das so machen. Ich ging davon aus, dass es bei dem "try: ...." explizit 2 sein müssen, aber wie gesagt, die vorherigen und nachfolgenden Zeilen waren nicht von mir.

    Den nmap Befehl habe ich abgeändert da es eigentlich nur wichtig ist ob "host up)" in der Ausgabe vor kommt - wir müssen nicht explizit die 1 heraus fischen.


    Achso, ja True und False geht ja auch.. Daran hab ich gar nicht gedacht :blush:



    Insofern solltest du noch mal prüfen ob das wirklich fehlerfrei bei dir funktioniert.


    Hmm komisch, bei mir funktioniert das einwandfrei. Kommt manchmal vor, dass es beim ersten Versuch nicht auf anhieb gelingt.Für die IP 192.168.178.99 (existiert nicht), bekomm ich keine Ausgabe, was ja auch so gewollt ist, oder?
    [code=php]pi@glancr:~ $ sudo nmap -F -Pn -sF 192.168.178.99 | grep "host up)"
    pi@glancr:~ $ sudo nmap -F -Pn -sF 192.168.178.20 | grep "host up)"
    Nmap done: 1 IP address (1 host up) scanned in 2.38 seconds
    pi@glancr:~ $
    [/php]


    Hab mir auch erlaubt für deine prints eine Funktion zu setzen, falls du später mal das Design ändern willst brauchst du das nur ein mal anpassen ;)


    Ach cool.. Das kann ich mir gleich mal aufschreiben. Sowas kann man immer mal brauchen :danke_ATDE:


    Danke für deine Bemühungen :thumbs1: Ich hab das Skript mal im Terminal gestartet und der erste Durchgang (ohne die Geräte im LAN) funktioniert fehlerfrei, aber wenn eines der Geräte im Netzwerk ist, dann erhalte ich diesen Fehler:
    [code=php]2017-04-20 13:11:54.020502: Bewegung erkannt!
    2017-04-20 13:11:56.022632: Suche Gerät1 ...
    2017-04-20 13:11:56.022994: <5> Suche Gerät: 192.168.178.31
    2017-04-20 13:12:03.929411: Gerät 1: GEFUNDEN
    2017-04-20 13:12:03.929939: Suche Gerät2 ...
    2017-04-20 13:12:03.930208: <5> Suche Gerät: 192.168.178.20
    2017-04-20 13:12:08.295498: Gerät 2: GEFUNDEN
    2017-04-20 13:12:08.296476: Kein Alarm! Mindestens ein Gerät wurde im Netzwerk gefunden
    2017-04-20 13:12:08.296969: Warte 5 Minuten
    [...]
    2017-04-20 13:34:20.351873: Bewegung erkannt!
    2017-04-20 13:34:22.354736: Suche Gerät1 ...
    2017-04-20 13:34:22.355234: <5> Suche Gerät: 192.168.178.20
    Traceback (most recent call last):
    File "/usr/bin/bewegungsmelder3.py", line 61, in <module>
    device1 = finde_geraet(geraet_1)
    File "/usr/bin/bewegungsmelder3.py", line 28, in finde_geraet
    response = subprocess.check_output('/usr/bin/nmap -F -Pn -sF %s | grep "host up)"' % IP, shell=True)
    File "/usr/lib/python2.7/subprocess.py", line 573, in check_output
    raise CalledProcessError(retcode, cmd, output=output)
    subprocess.CalledProcessError: Command '/usr/bin/nmap -F -Pn -sF 192.168.178.20 | grep "host up)"' returned non-zero exit status 1
    [/php]

  • Hm komisch... Ein Return-/Exit- code > 0 signalisiert immer einen Fehler...

    Dann versuchen wirs noch mal anders - ein klein wenig komplexer aber dafür hoffentlich besser :daumendreh2:

    [code=php]
    #!/usr/bin/python
    # -*- coding: utf-8 -*-

    import time
    import datetime
    import telepot
    import shlex
    from subprocess import Popen, PIPE
    from RPi import GPIO

    geraet_1 = '192.168.178.31'
    geraet_2 = '192.168.178.20'

    # GPIO 7 = Bewegungsmelder
    # GPIO 11 = Relais
    GPIO_PIR = 7
    GPIO_MON = 11


    #Board Mode anstelle GPIO BCM Nummer
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(GPIO_PIR, GPIO.IN)
    GPIO.setup(GPIO_MON, GPIO.OUT)


    def finde_geraet(IP='127.0.0.1', count=5):
    command = shlex.split('/usr/bin/nmap -F -Pn -sF %s' % IP)
    while count > 0:
    returncode=None
    found=False
    print "%s: <%d> Suche Gerät: %s" % (datetime.datetime.now(), count, IP)
    process = Popen(command, stdout=PIPE, stderr=PIPE, bufsize=1)
    for output in iter(process.stdout.readline, b''):
    if "host up)" in output.strip():
    found=True
    if process is not None:
    returncode = process.poll()
    process.stdout.close()
    process.wait()
    if found:
    return True
    if (returncode is not None) and (returncode != 0):
    printD("Error! Returncode: %s" % returncode)
    count -= 1
    return False


    def handle(msg):
    if 'text' in msg and msg['text'] == '/start':
    with open('/tmp/bewegungsmelder_id.txt', 'w') as f:
    f.write(str(msg['chat']['id']))


    def printD(message):
    print "%s: %s" % (datetime.datetime.now(), message)


    Current_State = 0
    Previous_State = 0
    try:
    while True:
    Current_State = GPIO.input(GPIO_PIR)
    time.sleep(0.2)

    if Current_State==1 and Previous_State==0:
    printD("Bewegung erkannt!")
    Previous_State=1
    GPIO.output(GPIO_MON, GPIO.LOW)
    time.sleep(1)
    GPIO.output(GPIO_MON, GPIO.HIGH)
    time.sleep(1)

    printD("Suche Gerät1 ...")
    device1 = finde_geraet(geraet_1)
    if device1:
    printD("Gerät 1: GEFUNDEN")
    else:
    printD("Gerät 1: keine Antwort")

    printD("Suche Gerät2 ...")
    device2 = finde_geraet(geraet_2)
    if device2:
    printD("Gerät 2: GEFUNDEN")
    else:
    printD("Gerät 2: keine Antwort")

    if not device1 and not device2:
    printD("KEIN GERÄT GEFUNDEN! Starte den TelegramBot")

    bot = telepot.Bot('******')
    bot.message_loop(handle)
    printD("TelegramBot: Suche Empfänger-ID aus Liste ...")
    with open('/usr/bin/bewegungsmelder_id.txt', 'r') as idfile:
    chat_id=int(idfile.read())
    bot.sendMessage(chat_id, "\n========================\nACHTUNG!\nJemand ist zuhause!")
    printD("TelegramBot: Nachricht erfolgreich abgeschickt!")
    else:
    printD("Kein Alarm! Mindestens ein Gerät wurde im Netzwerk gefunden")

    printD("Warte 5 Minuten")
    time.sleep(300)

    elif Current_State==0 and Previous_State==1:

    printD("Fertig! Warte auf Bewegung...")
    Previous_State=0
    GPIO.output(GPIO_MON, GPIO.LOW)
    time.sleep(1)
    GPIO.output(GPIO_MON, GPIO.HIGH)
    time.sleep(1)

    except KeyboardInterrupt:
    print " Exit"
    GPIO.cleanup()
    [/php]
    => http://codepad.org/ckQ0LuTf

  • Wow, da bin ich echt baff.. Funktioniert einwandfrei. Hatte am Anfang nur ein paar Probleme, weil ich den Bot-Token nicht eingefügt hatte :blush: :lol:

    Nur damit ich es auch verstehe, du hast jetzt 'Popen' genommen, statt 'subprocess.check_output'. Kannst du mir kurz erklären, was daran anders ist? Ich hab zwar das hier gefunden http://www.python-kurs.eu/os_modul_shell.php, kann aber damit nur vermuten, dass die Ausgabe "so wie sie ist" mithilfe von 'stdout=PIPE' übernommen wird(?). Ist dann diese Variante weniger anfällig für Fehler oder einfach "neuer"? Und wenn man die Wahl hat, sollte man Popen bevorzugen?

    Nochmals Danke für deine Hilfe, ich bin immer noch fasziniert, dass das Skript funktioniert :danke_ATDE: :danke_ATDE: :danke_ATDE:

    /EDIT:
    Diejenigen, die das Skript auch einsetzen möchten: Die Anwesenheitserkennung durch WLAN ist für Android & iPhone ein echtes Problem, weil das WLAN der Geräte im Standby vollständig oder sporadisch deaktiviert wird - auch wenn in den Einstellungen was anderes gewählt wird. Betrifft jedes iPhone mit dem Update, welches vor ca. 3-4 Wochen verteilt wurde. Bei Android ist es schwieriger und extrem Geräteabhängig - bei dem einen Funktioniert es, beim anderen nicht. Einzig die WindowsPhones (mit Windows 10 Mobile) sind davon nicht betroffen und halten die WLAN Verbindung permanent aufrecht. Man könnte natürlich auch mehrere Geräte hinzufügen, um Fehlalarme auszuschließen. z.B. Mediaplayer, Laptops, etc.

    ...als Denkanstoß: Vielleicht wäre eine Anwesenheitserkennung mit Bluetooth eine Option oder per NFC/Hardwareschalter a.d. Haustüre manuell ein-/auschecken...

    Einmal editiert, zuletzt von nobody2311 (22. April 2017 um 07:46)

  • Schaust Du hier: https://docs.python.org/2.7/library/subprocess.html

    Da steht u.a.:

    Zitat


    subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False)

    Run command with arguments and return its output as a byte string.

    If the return code was non-zero it raises a CalledProcessError. The CalledProcessError object will have the return code in the returncode attribute and any output in the output attribute.

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!