I am writing python code on raspberry pi 3. I am registering an event on input channel 21, to check moisture detection. I am getting this error Runtime error:Failed to add edge detection.
My code is:
import RPi.GPIO as GPIO
import sys,os
import time
import datetime
channel = 21
led_output = 18
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(channel, GPIO.IN)
GPIO.setup(led_output, GPIO.OUT)
def callback(channel):
filehandle = open("output.txt", "w") or die ("Could not write out")
if GPIO.input(channel) == 1:
print ("Water Detected!")
filehandle.write("1")
GPIO.output(led_output, GPIO.LOW)
else:
print ("Water Not Detected!")
filehandle.write("0")
GPIO.output(led_output, GPIO.HIGH)
filehandle.close()
GPIO.add_event_detect(channel, GPIO.BOTH, bouncetime=300)
GPIO.add_event_callback(channel, callback)
print(GPIO.input(channel))
while True:
time.sleep(5)
When I reboot the Raspberry and run your code it works perfect.
Only after killing the process or CTRL-C keyboard interrupting and running it again the problem/error occurs. I think this has to do with the fact that you exit the program without cleaning up properly...
I got it working in case you exit the running the program with CTRL-C with the code below in which I included a GPIO.cleanup()
However...this unfortunately it does not cover the situation in which you simply kill the running programm...In that case you still need to reboot.
So there is room for improvement.
Please re-insert your own file management commands again.
import RPi.GPIO as GPIO
import sys,os
import time
import datetime
channel = 21
led_output = 18
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(channel, GPIO.IN)
GPIO.setup(led_output, GPIO.OUT)
def callback(channel):
if GPIO.input(channel) == 1:
print ("Water Detected!")
GPIO.output(led_output, GPIO.LOW)
else:
print ("Water Not Detected!")
GPIO.output(led_output, GPIO.HIGH)
GPIO.add_event_detect(channel, GPIO.BOTH, bouncetime=300)
GPIO.add_event_callback(channel, callback)
print(GPIO.input(channel))
try:
while True:
#main loop here with some (dummy) code
eg_set_a_dummy_variable = 0
except KeyboardInterrupt:
# here you put any code you want to run before the program
# exits when you press CTRL+C
print ("Program interrupted by CTRL-C")
except:
# this catches ALL other exceptions including errors.
# You won't get any error messages for debugging
# so only use it once your code is working
print ("Other error or exception occurred!")
finally:
# this ensures a clean exit and prevents your
# error "Runtime error:Failed to add edge detection"
# in case you run your code for the second time after a break
GPIO.cleanup()
# credits to:
# https://raspi.tv/2013/rpi-gpio-basics-3-how-to-exit-gpio-programs-cleanly-avoid-warnings-and-protect-your-pi
It is not very clean solution, but you can call GPIO.cleanup() at the start of your script too for case when your process was killed before and GPIO.cleanup() was not called.
Related
import RPi.GPIO as GPIO
import paho.mqtt.client as mqtt
import time
def privacyfunc():
# Pin Definitions:
led_pin_1 = 7
led_pin_2 = 21
but_pin = 18
# blink LED 2 quickly 5 times when button pressed
def blink(channel):
x=GPIO.input(18)
print("blinked")
for i in range(1):
GPIO.output(led_pin_2, GPIO.HIGH)
time.sleep(0.5)
GPIO.output(led_pin_2, GPIO.LOW)
time.sleep(0.5)
mqttBroker="mqtt.fluux.io"#connect mqtt broker
client=mqtt.Client("privacybtn") #create a client and give a name
client.connect_async(mqttBroker)#from the client -connect broker
while True:
client.publish("privacy", x)#publish this random number to the topic called temparature
print("Just published"+str(x)+"to Topc to privacy")#just print random no to topic temparature
break
def main():
# Pin Setup:
GPIO.setmode(GPIO.BOARD) # BOARD pin-numbering scheme
GPIO.setup([led_pin_1, led_pin_2], GPIO.OUT) # LED pins set as output
GPIO.setup(but_pin, GPIO.IN) # button pin set as input
# Initial state for LEDs:
GPIO.output(led_pin_1, GPIO.LOW)
GPIO.output(led_pin_2, GPIO.LOW)
GPIO.add_event_detect(but_pin, GPIO.FALLING, callback=blink, bouncetime=10)
print("Starting demo now! Press CTRL+C to exit")
try:
while True:
x=GPIO.input(18)
print(x)
# blink LED 1 slowly
GPIO.output(led_pin_1, GPIO.HIGH)
time.sleep(2)
finally:
GPIO.cleanup() # cleanup all GPIOs
if __name__ == '__main__':
main()
need to take this whole code into a function that can be accessed from another python file.plz, help me with this coding part.
In the new python file call import module where module is the name of the file. Like led_blink.py would be import led_blink
Then you can call the methods like so:
led_blink.blink(channel)
This is assuming the files are in the same folder.
Easiest way that I do this is to take a .py file and put it in the same directory you created the python script you are working with. From there you can do the following code from The_Python_File import *
Additionally note that the "The_Python_File" is the name of the .py file that contains the function you are trying to call, but you do not include .py when importing the file.
I am working with a raspberry pi with a relay with the incandescent bulb, buzzer, and button via SSH. The code is in a way that when I press a key from the keyboard the bulb and buzzer should be ON and when I press button both should get OFF. But my button code is not working properly.
And also I want to check the status of the relay using the interrupt and whenever the light on it should be sent a message to the database. But I don't know with interrupts. Below is my code. Please help me. Thanks in advance
import RPi.GPIO as GPIO
import time
in1 = 25 #GPIO25 pin22
buzzer=24 #GPIO24 PIN18
led=8 #GPIO8 PIN24
button=23 #GPIO23 PIN 16
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(in1, GPIO.OUT)
GPIO.setup(buzzer,GPIO.OUT)
GPIO.setup(led,GPIO.OUT)
#GPIO.setup(button,GPIO.IN,pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(button, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.output(in1, False)
GPIO.output(buzzer,False)
GPIO.output(led,False)
try:
GPIO.output(in1,False)
while True:
GPIO.output(in1,False)
# check from database whether it is effective or deffective .currently I have inputted from keyboard
variable=raw_input()
if variable=="a":
m=variable
for x in m:
GPIO.output(in1, True)
time.sleep(0.05)
GPIO.output(in1, False)
time.sleep(0.05)
GPIO.output(buzzer,True)
GPIO.output(led,True)
if in1==True || buzzer==True:
print "messge to database:pending"
#def my_callback(channel):
#if GPIO.input(button) == True:
GPIO.wait_for_edge(button, GPIO.FALLING)
#if variable=="b":
#while 1:
GPIO.output(in1,False)
GPIO.output(led,False)
GPIO.output(buzzer,False)
print "mesage to database:ack completed"
#else:
#pass
#else:
#pass
GPIO.output(in1,False)
except:
GPIO.cleanup()
GPIO.output(in1,False)
If there is any error in my code please help me to rectify that. Thanks
I'm new to Python.
I've a threaded callback code working fine on my raspi.
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
import time
from daemon import runner
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) # float switch goes down (closed to open) => low water level
GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_UP) # float switch goes up (opened to close) => high water level
def callback_lowlevel(channel):
if GPIO.input(channel):
print "Low water level in the sump detected"
else:
print "Water level in the sump returned to normal"
def callback_highlevel(channel):
if GPIO.input(channel):
print "High water level in the sump detected"
else:
print "Water level in the sump returned to normal"
GPIO.add_event_detect(23, GPIO.BOTH, callback=callback_lowlevel, bouncetime=1000)
GPIO.add_event_detect(24, GPIO.BOTH, callback=callback_highlevel, bouncetime=1000)
If I start an infinite loop like this:
try:
print "Waiting for events"
while True:
time.sleep(1)
except KeyboardInterrupt:
GPIO.cleanup() # clean up GPIO on CTRL+C exit
GPIO.cleanup() # clean up GPIO on normal exit
It works.
But if I "daemonize" it with the daemon library, my threaded callbacks are just not working anymore.
class App(): # Daemon content, not doing much, sleeping mostly, to lower CPU footprint
def __init__(self):
self.stdin_path = '/dev/null'
self.stdout_path = '/dev/stdout'
self.stderr_path = '/dev/stdout'
self.pidfile_path = '/var/run/aquamonitor.pid'
self.pidfile_timeout = 5
def run(self):
Logger("Starting monitoring")
while True:
time.sleep(1) # Sleep most of time to be not too CPU intensive
app = App() # Init the App
daemon_runner = runner.DaemonRunner(app) # Run as a daemon
daemon_runner.do_action() # Just do it
What am I doing wrong? Does the fact that it's a daemon changes the way I'm supposed to write my threaded callbacks?
I had the same issue and I figured I was registering the callback to the wrong thread. So, long story short, be sure that GPIO.add_event_detect is called from within the run method of your App class, just before the loop.
My project is to take the reading from the PIR sensor and play a song when the person is in front of the sensor but I cannot figure the logic behind this code that I found online and tried modifying it.
What I need to do is:
How do I loop this, omxp.poll() doesn't work :(
Edit: Now It stops but is there a way to loop the process and is there a way to make the script memory efficient
Here is the code:(updated)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#from subprocess import Popen
from omxplayer import OMXPlayer
import RPi.GPIO as GPIO
import time
import subprocess
GPIO.setmode(GPIO.BCM)
PIR_PIN = 7
GPIO.setup(PIR_PIN, GPIO.IN)
song = OMXPlayer('/home/pi/5Seconds.mp3')
try:
print ("Pir Module Test (CTRL+C to exit)")
time.sleep(2)
print("Ready")
active = False
while True:
time.sleep(2)
if GPIO.input(PIR_PIN):
time.sleep(1)
print("Motion detected")
if not active:
active = True
print("Music started")
song.play()
time.sleep(10)
elif active:
print("No motion detected, stop the music")
song.pause()
song.can_control(song)
active = False
if active and song.poll() != None: # detect completion to allow another start
print("Music finished")
active = False
except KeyboardInterrupt:
print ("Quit")
GPIO.cleanup()
Based on your original code, try the following, I have made a few minor changes to the way your script works:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from subprocess import Popen
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
PIR_PIN = 7
GPIO.setup(PIR_PIN, GPIO.IN)
song_path = '/home/pi/Hillsong.mp3'
try:
print ("Pir Module Test (CTRL+C to exit)")
time.sleep(2)
print("Ready")
active = False
while True:
if GPIO.input(PIR_PIN):
print("Motion detected")
if not active:
active = True
print("Music started")
omxp = Popen(['omxplayer', song_path])
elif active:
print("No motion detected, stop the music")
omxp.terminate()
active = False
if active and omxp.poll() != None: # detect completion to allow another start
print("Music finished")
active = False
time.sleep(5)
except KeyboardInterrupt:
print ("Quit")
GPIO.cleanup()
Note:
while True means loop forever, as such the time.sleep(10) following it would never be executed.
while False will never execute what is inside it, so omxp.terminate() would never be executed.
Use a variable active to indicate if the player is running to avoid multiple starts.
I do not have a Pi to hand so it has not been tested.
How can I remove the trackback from the command output, and how can I stop this looping in the atexit function?
!/usr/bin/python
import time, atexit, sys
import RPi.GPIO as GPIO
#16 = Motor 1 - Forward
#18 = Motor 1 - Back
#11 = Motor 2 - Forward
#13 = Motor 2 - Back
#6 = Ground
GPIO.setmode(GPIO.BOARD)
GPIO.setup(16, GPIO.OUT)
GPIO.setup(18, GPIO.OUT)
GPIO.setup(11, GPIO.OUT)
GPIO.setup(13, GPIO.OUT)
def exit_handler():
GPIO.cleanup()
print 'STOPPED'
while True:
GPIO.output(11, True)
GPIO.output(16, True)
print "Forward"
time.sleep(5)
atexit.register(exit_handler)
It seems to work OK, and runs the motor controller on my Pi (just - due to dodgy wiring
)
But when I run it, I get this as the output:
[wilf#Pi MovementCommands]$ 1/forward.py
Forward
Forward
Forward
Forward
Forward
Forward
Forward
Forward
Forward
Forward
Forward
Forward
Forward
Forward
Forward
Forward
Forward
Forward
Forward
^CTraceback (most recent call last):
File "1/forward.py", line 17, in <module>
time.sleep(5)
KeyboardInterrupt
STOPPED
STOPPED
STOPPED
STOPPED
STOPPED
STOPPED
STOPPED
STOPPED
STOPPED
STOPPED
STOPPED
STOPPED
STOPPED
STOPPED
STOPPED
STOPPED
STOPPED
STOPPED
[wilf#Pi MovementCommands]$
For some reason it seems to be looping the exit_handler nearly as many times as the main bit loops - how can I stop it doing this - it can take ages to exit if it has be running for a while, as it loops the cleanup command. (The main bit does not have to loop, but it is useful as visual indication that it is doing something - could I possibly just loop the print bit...).
I also seem to be unable to stop the traceback of atexit being displayed, without having to use except KeyboardInterrupt. This would be useful anyway, but I may later want to automate it by running it from a Bash script (yes I could integrate it into it, but I don't want to).
You are re-registering the atexit handler each time your loop iterates. Python calls the function as many times as it has been registered.
Register the function just once. You don't need to call sys.exit(0) in your atexit function either, you are already exiting your program.
Corrected program:
import time, atexit
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
def exit_handler():
GPIO.cleanup()
print 'STOPPED'
atexit.register(exit_handler)
while True:
GPIO.output(11, True)
GPIO.output(16, True)
print "Forward"
time.sleep(5)
Alternatively, catch the KeyboardInterrupt and clean up in the exception handler:
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
try:
while True:
GPIO.output(11, True)
GPIO.output(16, True)
print "Forward"
time.sleep(5)
except KeyboardInterrupt:
pass # silence the interrupt
finally:
GPIO.cleanup()
print 'STOPPED'
The finally block calls GPIO.cleanup() regardless of what exception occurred, the except KeyboardInterrupt just silences the keyboard interrupt exception.
Note that the traceback was never in the atexit() function, it is the reason the program is exiting and why atexit() is called at all. In other words, the exception preceeds the atexit() function call.