Alias-Befehl im .bash_aliases zeigt keine Reaktion, Raspberry 3B Stretch

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
JoPi
User
Beiträge: 2
Registriert: Sonntag 17. Februar 2019, 10:29

Hi,

Ich brauche Hilfe.
Ein endlos laufendes Python-Skript wird über einen Alias-Befehl vom Terminal aus gestartet.
Der Alias-Befehl lautet: pidon und funktioniert einwandfrei.
Hier der Inhalt von .bash_alisaes

pi@pi3solar:~ $ cat .bash_aliases
alias pidon='sudo python3 /home/pi/aPy/test_scripts/GPIO/PID_EMAIL_3.py &'
alias pidoff='ps -elf | grep /home/pi/aPy/test_scripts/GPIO/PID_EMAIL_3.py | awk '{print $4}' | xargs sudo kill'

Der Alias-Befehl "pidoff" hingegen, funktioniert nicht, keine Reaktion!
Wenn die den Alias-Befehl representierende Komandozeile im Terminal Fenster
ausgeführt wird, dann stop das Script.

Hier ist das Python Script: (Ver.3.5.3)

#!/usr/bin/env python3

import RPi.GPIO as GPIO
from time import sleep, perf_counter
from datetime import datetime


GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM) # is the GPIO-name, NOT the Pin
SW_GPIO = 12 # pin32 & pin30 is GND
GPIO.setup(SW_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)

def email():
import smtplib
server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
server.ehlo()
server.login("k10101305dak@gmail.com","vwkpeqgdwbarvjsg")
SUBJECT = "Warnung des Bewegungsmelders"
TEXT = "Achtung !! der Bewegungsmelder hat eine Bewegung erkannt."
msg = 'Subject: {}\n\n{}'.format(SUBJECT, TEXT)
#server.sendmail("k10101305dak@gmail.com","wallieschen@gmail.com", msg)
#server.sendmail("k10101305dak@gmail.com","wasserpop@gmx.de", msg)
server.quit()

print(' Email has been send:',datetime.now())


movement = 0
active = 0
wait = 180 #__in seconds when sleep < 1 sec__
start = perf_counter() - wait
loop = True
print(' Go -> ')

if __name__ == '__main__':
try:
while loop:
movement = GPIO.input(SW_GPIO)
#print('PIR',movement)
if movement == 1 and active == 0:
actual = perf_counter()
print(' movement',movement)
if actual - start > wait:
email()
active = 1
start = perf_counter()
elif movement == 0 and active == 1:
print(' PIR free')
active = 0
elif movement == 1 and active == 1:
print(' PIR blocked')
actual = perf_counter()
if actual - start > wait:
active = 0
sleep(0.3)

except KeyboardInterrupt:
loop = False
print('\n Bye')
GPIO.cleanup()

Hat jemand eine Idee warum, gibt es Alternativen?
Grüsse
Benutzeravatar
DeaD_EyE
User
Beiträge: 1257
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Bitte Code-Tags verwenden, damit die Einrückung erhalten bleibt.

Ich würde das ganz anders machen. Systemd kann man so konfigurieren, dass normale Benutzer auch Dienste mit den Rechten des aktuellen Benutzers starten können.
Soweit ich weiß, muss man es bei Raspberry Pi OS aktivieren: https://wiki.archlinux.org/title/System ... _instances

Dann schreibst du eine Unit-File:
~/.config/systemd/user/email.service

Code: Alles auswählen

[Unit]
Description=PID EMAIL 3

[Service]
ExecStart=/usr/bin/python3 -u /home/pi/aPy/test_scripts/GPIO/PID_EMAIL_3.py

[Install]
WantedBy=default.target
Der Optionsschalter -u deaktiviert den Puffer für sdtout und stderr.
Dann sieht man Ausgaben durch print und Tracebacks sofort. Ohne den Optionsschalter muss man warten bis der Puffer voll ist und wenn man Pech hat, gibt das Programm so wenig aus, dass nie etwas angezeigt wird.

Dann muss man einmal den Daemon neu laden. Das sollte man als normaler user machen können:

Code: Alles auswählen

systemctl --user daemon-reload
Starten kannst du den Dienst dann so:

Code: Alles auswählen

systemctl --user start email
Stoppen:

Code: Alles auswählen

systemctl --user stop email
Das kannst du dir dann als Alias anlegen und falls du möchtest, kannst du auch mit Timer arbeiten. Wenn der Dienst z.B. nur zwischen 8 unr 16 Uhr laufen soll.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Benutzeravatar
__blackjack__
User
Beiträge: 14131
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@JoPi: Du hast bei ``pidoff`` einfache Anführungszeichen *in* einer Zeichenkette die in einfache Anführungszeichen eingefasst ist. Das geht so nicht. Hier mal ein Beispiel wie man das machen kann:

Code: Alles auswählen

echo 'O'\''Reilly'
Alternativ könnte man das in doppelte Anführungszeichen einfassen und das ``$``-Zeichen escapen.

Die von DeaD_EyE vorgeschlagene Lösung ist aber besser.

Anmerkungen zum Python-Quelltext:

``as`` beim Importieren ist zum umbenennen, GPIO wird aber gar nicht umbenannt.

Importe und Konstanten gehören an den Anfang des Moduls, nicht in Funktionen.

Warnungen sollte man nicht ignorieren, sondern die Ursache beseitigen.

Die Einrückung sollte einheitlich 4 Leerzeichen pro Ebene sein.

Das *gesamte* Hauptprogramm sollte durch den ``if __name__ == …``-Guard geschützt sein *und* in einer Funktion stehen, damit nicht alles mögliche Modulglobal definiert wird.

Der ``try``-Block wo im ``finally`` die GPIOs aufgeräumt werden, sollte grösser sein, denn zwischen GPIOs aufsetzen und ``try`` steht Code der Ausnahmen auslösen könnte und dann wird nicht aufgeräumt. `GPIO.cleanup()` darf man immer aufrufen, der Benutzer könnte immer Strg+C drücken, also kann man auch einfach das gesamte Hauptprogramm in den ``try``-Block setzen.

Python hat einen eigenen Datentyp für Wahrheitswerte, den sollte man auch benutzen und nicht 0 und 1 dafür missbrauchen. Bei `loop` wird das ja gemacht. Man vergleicht dann auch nicht mit den literalen Wahrheitswerten, sondern benutzt entweder den Wert selbst, oder seine Negation.

`loop` ist unsinnig. Das in der Schleife niemals verändert und an der Stelle wo `False` zugewiesen wird, ist die Schleife schon längst verlassen.

`actual` ist ziemlich sicher der falsche Name. Das heisst auf Deutsch nicht „aktuell“ sondern „tatsächlich“.

Insgesamt ist das „busy waiting“ sehr unschön. Man kann sich auch über steigende und fallende Flanken informieren lassen ohne da selbst drauf warten zu müssen. `gpiozero` statt `RPi.GPIO` wäre noch besser.

`SMTP_SSL`-Objekte sind Kontextmanager, die sollte man mit der ``with``-Anweisung verwenden.

Namen sollten nicht kryptisch abgekürzt werden. Wenn man `message` meint, sollte man nicht nur `msg` schreiben.

`format()` braucht man nur, wenn die Vorlage variabel ist. Sonst kann man das einfach als f-Zeichenkettenliteral schreiben.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import smtplib
from datetime import datetime as DateTime
from time import perf_counter, sleep

from RPi import GPIO

SW_GPIO = 12  # pin32 & pin30 is GND
SUBJECT = "Warnung des Bewegungsmelders"
TEXT = "Achtung !! der Bewegungsmelder hat eine Bewegung erkannt."
SMTP_HOST = "smtp.gmail.com"
SMTP_USER = SENDER_EMAIL = "k10101305dak@gmail.com"


def email():
    with smtplib.SMTP_SSL(SMTP_HOST, 465) as server:
        server.ehlo()
        server.login(SMTP_USER, "vwkpeqgdwbarvjsg")
        message = f"Subject: {SUBJECT}\n\n{TEXT}"
        # server.sendmail(SENDER_EMAIL, "wallieschen@gmail.com", message)
        # server.sendmail(SENDER_EMAIL, "wasserpop@gmx.de", message)

    print(" Email has been send:", DateTime.now())


def main():
    try:
        GPIO.setmode(GPIO.BCM)  # is the GPIO-name, NOT the Pin
        GPIO.setup(SW_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)
        movement = False
        active = False
        wait_time = 180  # in seconds when sleep < 1 sec
        start_timestamp = perf_counter() - wait_time
        print("  Go ->")
        while True:
            movement = GPIO.input(SW_GPIO)
            # print('PIR',movement)
            if movement and not active:
                current_timestamp = perf_counter()
                print(" movement", movement)
                if current_timestamp - start_timestamp > wait_time:
                    email()
                    active = True
                    start_timestamp = perf_counter()
            elif not movement and active:
                print(" PIR free")
                active = False
            elif movement and active:
                print(" PIR blocked")
                current_timestamp = perf_counter()
                if current_timestamp - start_timestamp > wait_time:
                    active = False
            sleep(0.3)

    except KeyboardInterrupt:
        GPIO.cleanup()
        print("\n  Bye")


if __name__ == "__main__":
    main()
“It is easier to change the specification to fit the program than vice versa.” — Alan J. Perlis
Antworten