nach Korrektur meines Tippfehlers geht nichts, PIR wird nicht ausgelöst.
Kannst du dazu das Script posten? Alles andere ist raten.
nach Korrektur meines Tippfehlers geht nichts, PIR wird nicht ausgelöst.
Kannst du dazu das Script posten? Alles andere ist raten.
nohup? Schau mal ob du hier fündig wirst!
hier das Script:
#!/usr/bin/python3
import logging
import smtplib
from email.header import Header
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from functools import partial
from pathlib import Path
from signal import pause
from socket import gaierror
from time import sleep
import picamera
from gpiozero import DigitalOutputDevice, MotionSensor
from pushbullet import Pushbullet
logging.basicConfig(
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
level=logging.INFO,
)
PATH_TO_PICTURE = Path("/home/pi/bild1.jpg")
MOTION_PIN = 11
RELAIS_PIN = 17
MAIL_FROM = "my email address"
MAIL_TO = "my email address"
SMTP_HOST = "mein Postausgangsserver"
SMTP_PORT = 465
SMTP_USER = "my user name"
SMTP_PASSWORD = "my password"
MAIL_SUBJECT = "von RPI 3 Home1"
MESSAGE_TEXT = "Foto von RPI 3 Home1"
PUSHBULLET_API_KEY = "mein neuer API key"
PHONE_NUMBER = "my mobile number"
def get_picture(ir_light, camera):
camera.rotation = 90
try:
ir_light.on()
try:
sleep(0.5)
camera.capture(str(PATH_TO_PICTURE), resize=(740, 480))
finally:
ir_light.off()
logging.info("Foto aufgenommen")
except picamera.exc.PiCameraError:
logging.exception("Camera Fehler")
def push_to_bullet(push_bullet):
try:
push_bullet.push_sms(
push_bullet.devices[0], PHONE_NUMBER, "RPI 3 Home1 ausgeloest"
)
logging.info("sms gesendet")
except Exception:
logging.exception("sms Fehler")
def send_mail():
message = MIMEMultipart()
message["From"] = MAIL_FROM
message["To"] = MAIL_TO
message["Subject"] = Header(MAIL_SUBJECT)
message.attach(MIMEText(MESSAGE_TEXT))
message.attach(MIMEImage(PATH_TO_PICTURE.read_bytes()))
logging.info("Foto angehaengt")
try:
with smtplib.SMTP_SSL(SMTP_HOST, SMTP_PORT) as smtp:
smtp.login(SMTP_USER, SMTP_PASSWORD)
smtp.sendmail(MAIL_FROM, MAIL_TO, message.as_string())
logging.info("e-mail gesendet")
except gaierror:
logging.exception("e-mail Fehler")
def on_motion(push_bullet, ir_light, camera):
try:
logging.info("PIR 3 Home1 wurde ausgeloest")
get_picture(ir_light, camera)
push_to_bullet(push_bullet)
send_mail()
except Exception:
logging.exception("Unerwartete Ausnahme!")
#def on_no_motion():
#logging.info("im Schlafmodus")
def main():
motion_sensor = MotionSensor(MOTION_PIN)
ir_light = DigitalOutputDevice(RELAIS_PIN)
push_bullet = Pushbullet(PUSHBULLET_API_KEY)
with picamera.PiCamera() as camera:
try:
motion_sensor.wait_for_motion = partial(
on_motion, push_bullet, ir_light, camera
)
#motion_sensor.when_no_motion = on_no_motion
pause()
except KeyboardInterrupt:
pass
if __name__ == "__main__":
main()
Alles anzeigen
Hallo,
'wait_for_motion' funktioniert so nicht. In der Doku steht dazu:
ZitatPause the script until the device is activated, or the timeout is
reached.
https://gpiozero.readthedocs.io/en/stable/api_…ensor-d-sun-pir
Dein Programm wird solange angehalten, bis eine Bewegung erkannt wird. Du musst dann die Funktion 'on_moition' danach aufrufen, wenn das Programm fortgesetzt wird. Wenn du das so verwenden willst, dann muss das in eine Schleife, damit das Programm danach wieder wartet.
def main():
motion_sensor = MotionSensor(MOTION_PIN)
ir_light = DigitalOutputDevice(RELAIS_PIN)
push_bullet = Pushbullet(PUSHBULLET_API_KEY)
with picamera.PiCamera() as camera:
try:
while True:
motion_sensor.wait_for_motion()
on_motion(push_bullet, ir_light, camera)
except KeyboardInterrupt:
pass
Alles anzeigen
Grüße
Dennis
ja, funktioniert bis auf die Tatsache, dass nach der ersten Bewegung
am PIR das Script in der while Schlaufe endlos abläuft.
ist mir noch aufgefallen, dass die partial Funktion nicht mehr
gebraucht wird ?
Genau, wait_for_motion() funktioniert anders als when_no_motion.
mit der Funktionalität des Scripts wie folgt kann ich gut leben,
Störmeldungen sind nicht mehr aufgetreten und das Problem des
Script Abbruches ist mit einer service unit gelöst:
https://gist.github.com/luemar/17d7659…fb4f4259aadefd3
Allen Experten nochmals herzlichen Dank .
Die Schleife Zeile 95 ist überflüssig.
hatte initial keine while Schleife, dann passierte gar nichts. Erst nach Einfügen der
Schleife funktionierts.
In dieser vergangenen Themenfolge habe ich auf diesem ausgezeichneten Forum
viel gelernt und begriffen, anfänglich hatte ich nur Code abgeschrieben/kopiert.
Habe erkennen müssen, dass mein aktuelles Script mit pir.when_pressed() und
pir.when_released() mein Ziel doch nicht erfüllt. Ich brauche pir.when_held
um mit einer hold_time von einigen Sekunden, die von der PIR-Haltezeit immer
übertroffen wird, die viel kürzeren Störimpulse zu unterdrücken.
Nur schaffe ich das noch nicht, folgendes Testscript, aus einem anderen Projekt übernommen
zeigt keine Reaktion:
#!/usr/bin/python3
from gpiozero import Button
from signal import pause
button = Button(11, hold_time = 2)
Button.was_held = False
def test_on(button):
print('test aufgerufen')
Button.was_held = True
print('Funktionen')
def test_off(button):
if not button.was_held:
Button.was_held = False
def main():
button.when_held = test_on
button.when_released = test_off
pause()
print('Init abgeschlossen')
if __name__ == "__main__":
main()
Alles anzeigen
Hallo,
'Button' hat gar kein 'was_held' :
https://gpiozero.readthedocs.io/en/stable/api_input.html#button
Du solltest nicht irgendwas an der 'Button'-Klasse hinzufügen oder überschreiben.
Du benötigst das auch nicht, weil du einfach 'value' abfragen kannst, da bekommst du je nach gedrückt oder nicht eine 1 oder eine 0 ausgegeben.
Was passiert, wenn du den Button jetzt 2 Sekunden gedrückt hälst?
#!/usr/bin/python3
from gpiozero import Button
from signal import pause
def test_on(button):
print("Button wurde gedrückt")
def main():
button = Button(11, hold_time=2)
button.when_held = test_on
pause()
if __name__ == "__main__":
main()
Alles anzeigen
Grüße
Dennis
Um das nicht liegen zu lassen.
def main():
motion_sensor = MotionSensor(MOTION_PIN)
ir_light = DigitalOutputDevice(RELAIS_PIN)
push_bullet = Pushbullet(PUSHBULLET_API_KEY)
with picamera.PiCamera() as camera:
try:
motion_sensor.when_motion = partial(
on_motion, push_bullet, ir_light, camera
)
motion_sensor.when_no_motion = on_no_motion
pause()
except KeyboardInterrupt:
pass
if __name__ == "__main__":
main()
Alles anzeigen
Das muss so laufen. hat ja vorher auch funktioniert. Die while - Schleife ist da tatsächlich überflüssig.
ja, das funktioniert im Prinzip: Die Funktion test_on(button)
wird aufgerufen, aber erst nach Ablauf der Haltezeit des PIR, ich hatte
erwartet nach Ablauf der hold_time bzw. nach 2 Sekunden.
Aber die Idee zur Unterdrückung von Störimpulsen scheint trotzdem
zu funktionieren: Habe die hold_time auf 65 sec gesetzt, 5 sec länger
als die PIR-Haltezeit (z. Z. 60 sec) um so einen Störimpuls zu simulieren
und die Funktion wird nicht aufgerufen.
Das heisst aber, dass in meiner definitiven Installation eine (unbefugte)
Bewegung erst nach Ablauf der PIR-Haltezeit die verschiedenen
Funktionen, Foto, SMS etc. erfolgen. Die PIR Haltezeit ist verkürzbar.
Habe mittlerweile von MotionSensor auf Button gewechselt. S.O.
Nun das Sript entsprechend angepasst, mit dem selben Test
Resultat wie in #70 und #72 :
Und wieder ist diese unnötige Schleife da. Damit produzierst Du nur sinnlose Prozessorlast.
ich sags jetzt zum x-ten Mal: Wenn ich die while Schleife weglasse passiert
nach einer Bewegung am PIR nichts...
Dann noch mein letzter Punkt, ein 2. thread zur Aufnahme und e-mail Versenden
eines Fotos täglich/nächtlich zu vorgegebener Zeit:
Habe den def main() Block in Anlehnung an eine andere Installation ergänzt
nach import von schedule und threading:
def main():
pir = Button(BUTTON_PIN, hold_time=65)
ir_light = DigitalOutputDevice(RELAIS_PIN)
push_bullet = Pushbullet(PUSHBULLET_API_KEY)
with picamera.PiCamera() as camera:
schedule.every().day.at("21:49").do(get_picture(ir_light,camera),
send_mail())
threading.Thread(target=schedule_thread).start()
try:
while True:
pir.when_held = partial(on_motion, push_bullet, ir_light,
camera)
pause()
except KeyboardInterrupt:
pass
if __name__ == "__main__":
main()
Alles anzeigen
erstaunlicherweise werden beide Funktionen get_picture(ir_light, camera und
send_mail() unmittelbar nach Aktivierung des Scripts ausgeführt, unabhängig
von der eingegebenen Zeit und das Script bricht ab mit:
root@raspberrypiZeroHome1:/home/pi# python3 onMotion_v0.py
2023-05-19 21:52:14,563 - root - INFO - Foto aufgenommen
2023-05-19 21:52:14,674 - root - INFO - Foto angehaengt
2023-05-19 21:52:15,357 - root - INFO - e-mail gesendet
Traceback (most recent call last):
File "/home/pi/onMotion_v0.py", line 111, in <module>
main()
File "/home/pi/onMotion_v0.py", line 100, in main
schedule.every().day.at("21:54").do(get_picture(ir_light,camera), send_mail())
File "/usr/local/lib/python3.9/dist-packages/schedule/__init__.py", line 657, in do
self.job_func = functools.partial(job_func, *args, **kwargs)
TypeError: the first argument must be callable
Möglicherweise ist in der schedule Methode in Argument zuviel ?
ich sags jetzt zum x-ten Mal: Wenn ich die while Schleife weglasse passiert
nach einer Bewegung am PIR nichts...
Dann hast Du was falsch gemacht! Und jetzt hast Du auch noch das Signal pause() in der Schleife.
Btw. Die hold_time muss kürzer eingestellt sein als die Dauer der Flanke des PIR, sonst löst pir.when_held nie aus.
Moment, schedule muss doch in einer Schleife laufen, wenn ich das richtig in Erinnerung habe.
erstaunlicherweise werden beide Funktionen get_picture(ir_light, camera und
send_mail() unmittelbar nach Aktivierung des Scripts ausgeführt, unabhängig
von der eingegebenen Zeit und das Script bricht ab mit:
Das ist nicht erstaunlich, sondern das ist genau das was du programmiert hast. Wenn der Interpreter das erste mal deinen Code durchgeht, dann sieht er einen Funktionsaufruf und ruft die Funktion auf. Ein Klammerpaar nach einem Funktionsname bedeutet, dass die Funktion aufgerufen werden soll.
Stichwort: 'partial', falls 'sheudel da nicht was anbietet um Argumente mit zu übergeben. Schau mal in die Doku dazu.
Grüße
Dennis
Versuch mal das:
def main():
pir = Button(BUTTON_PIN, hold_time=65)
ir_light = DigitalOutputDevice(RELAIS_PIN)
push_bullet = Pushbullet(PUSHBULLET_API_KEY)
with picamera.PiCamera() as camera:
def task():
get_picture(ir_light, camera), send_mail()
# do verlangt offensichtlich nach einer Funktion
schedule.every().day.at("21:49").do(task)
threading.Thread(target=schedule_thread).start()
pir.when_held = partial(on_motion, push_bullet, ir_light, camera)
try:
pause()
except KeyboardInterrupt:
pass
if __name__ == "__main__":
main()
Alles anzeigen
ich sags jetzt zum x-ten Mal: Wenn ich die while Schleife weglasse passiert
nach einer Bewegung am PIR nichts...
Wenn dir mehrere Leute über 2 Threads sagen, das die while-Schleife Unsinn ist, dann ist da sicher etwas dran.
Da solltest du mal schauen was an deinem Programmaufbau nicht stimmt. Die sagen das nicht um dich zu ärgern.
Vllt wäre es hilfreich, wenn du dir den Unterschied von:
button.when_pressed = funktion
button.when_released = funktion
button.when_held = funktion
pause()
und
while True:
button.wait_for_press() # pausiere bis Input
#mach was
if anderer_button.is_pressed:
#mach was mit anderen Button
elif:
#andere_button wurde nicht gedrückt
nochmal anschaust.
Schedule bietet auch decoratoren. Ob das wie folgt funktioniert weiß ich nicht. Du solltest aber überlegen ob Foto schießen und gleichzeitig senden sinnvoll ist oder ob das nicht zeitlich etwas versetzt passieren sollte.
#!/usr/bin/python3
import logging
import smtplib
from email.header import Header
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from functools import partial
from pathlib import Path
from socket import gaierror
from time import sleep
import picamera
from gpiozero import Button
from pushbullet import Pushbullet
import schedule
from time import sleep
logging.basicConfig(
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
level=logging.INFO,
)
PATH_TO_PICTURE = Path("/home/pi/bild1.jpg")
MOTION_PIN = 11
RELAIS_PIN = 17
MAIL_FROM = "my email address"
MAIL_TO = "my email address"
SMTP_HOST = "Mein Post Ausgangsserver"
SMTP_PORT = 465
SMTP_USER = "my username"
SMTP_PASSWORD = "my password"
MAIL_SUBJECT = "von RPI 3 Home1"
MESSAGE_TEXT = "Foto von RPI 3 Home1"
PUSHBULLET_API_KEY = "my access token"
PHONE_NUMBER = "my mobile number"
@repeat(every().day.at("21:49"))
def get_picture(ir_light):
with picamera.PiCamera() as camera:
camera.rotation = 90
try:
ir_light.on()
try:
sleep(0.5)
camera.capture(str(PATH_TO_PICTURE), resize=(740, 480))
finally:
ir_light.off()
logging.info("Foto aufgenommen")
except picamera.exc.PiCameraError:
logging.exception("Camera Fehler")
def push_to_bullet(push_bullet):
try:
push_bullet.push_sms(
push_bullet.devices[0], PHONE_NUMBER, "RPI 3 Home1 ausgeloest"
)
logging.info("sms gesendet")
except Exception:
logging.exception("sms Fehler")
@repeat(every().day.at("21:50"))
def send_mail():
message = MIMEMultipart()
message["From"] = MAIL_FROM
message["To"] = MAIL_TO
message["Subject"] = Header(MAIL_SUBJECT)
message.attach(MIMEText(MESSAGE_TEXT))
message.attach(MIMEImage(PATH_TO_PICTURE.read_bytes()))
logging.info("Foto angehaengt")
try:
with smtplib.SMTP_SSL(SMTP_HOST, SMTP_PORT) as smtp:
smtp.login(SMTP_USER, SMTP_PASSWORD)
smtp.sendmail(MAIL_FROM, MAIL_TO, message.as_string())
logging.info("e-mail gesendet")
except gaierror:
logging.exception("e-mail Fehler")
def on_motion(push_bullet, ir_light):
try:
logging.info("PIR 3 Home1 wurde ausgeloest")
get_picture(ir_light)
push_to_bullet(push_bullet)
send_mail()
except Exception:
logging.exception("Unerwartete Ausnahme!")
def main():
pir = Button(BUTTON_PIN, hold_time=65)
ir_light = DigitalOutputDevice(RELAIS_PIN)
push_bullet = Pushbullet(PUSHBULLET_API_KEY)
try:
pir.when_held = partial(on_motion, push_bullet, ir_light)
while True:
schedule.run_pending()
sleep(1)
except KeyboardInterrupt:
pass
if __name__ == "__main__":
main()
Alles anzeigen
Alternative:
Die Decoratoren wieder entfernen (@repeat(every().day.at()) und die main() ändern.
import schedule
def main():
pir = Button(BUTTON_PIN, hold_time=65)
ir_light = DigitalOutputDevice(RELAIS_PIN)
push_bullet = Pushbullet(PUSHBULLET_API_KEY)
try:
pir.when_held = partial(on_motion, push_bullet, ir_light)
schedule.every().day.at("21:49").do(get_picture, ir_light)
schedule.every().day.at("21:50").do(send_mail)
while True:
schedule.run_pending()
sleep(1)
except KeyboardInterrupt:
pass
if __name__ == "__main__":
main()
Alles anzeigen
Mit Thread:
from threading import Thread
import schedule
def schedule_thread():
while True:
schedule.run_pending()
sleep(1)
def main():
pir = Button(BUTTON_PIN, hold_time=65)
ir_light = DigitalOutputDevice(RELAIS_PIN)
push_bullet = Pushbullet(PUSHBULLET_API_KEY)
try:
pir.when_held = partial(on_motion, push_bullet, ir_light)
schedule.every().day.at("21:49").do(get_picture, ir_light)
schedule.every().day.at("21:50").do(send_mail)
threading.Thread(target=schedule_thread, deamon=True).start()
pause()
except KeyboardInterrupt:
pass
if __name__ == "__main__":
main()
Alles anzeigen
Wobei ich nicht glaube das du hier unbedingt einen Thread brauchst.
Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!