Hi I'm learning to code python on raspberry pi 3 model B. and playing around with GPIO.
My script makes a LED turns on when the receiving input==1 and turn off when input!=1.
I also want to record the time when LED is turned on and time when it's turned off. (start time and end time).
I end up using multiple if/elif condition, but I'm sure there are better ways of doing this. Please enlighten me!
import RPi.GPIO as GPIO
import time
GPIO.cleanup()
GPIO.setmode(GPIO.BOARD)
GPIO.setup(11,GPIO.IN, pull_up_down = GPIO.PUD_DOWN)
GPIO.setup(7,GPIO.OUT)
GPIO.output(7,0) #set ping 7 to be 0 at default
CatchTime = True
startTime = []
startTimeRead = []
endTime = []
try:
while True:
time.sleep(0.25)
if (GPIO.input(11) ==1)and CatchTime==True : #start counting
GPIO.output(7,1)
print(time.ctime())
startTime.append(time.time())
startTimeRead.append(time.ctime())
CatchTime = False
elif (GPIO.input(11) ==1)and CatchTime != True : #within count
GPIO.output(7,1)
print(time.ctime())
elif (GPIO.input(11) !=1) and CatchTime != True : #end of count
GPIO.output(7,0)
CatchTime = True
endTime.append(time.time())
else: #steady not count
GPIO.output(7,0)
CatchTime = True
except KeyboardInterrupt:
GPIO.cleanup()
print('start time:',startTimeRead)
print('end time:',endTime)
Generally the better way to do it would be to create interrupt functions for the rising and falling events. what you're doing now is referred to as busy waiting while polling for an input. Interrupts are generally cleaner and more reliable. Computerphile has a nice overview on interrupts in general (more from the computer aspect of things), and a quick google search found this tutorial on how to use gpio interrupts with the rasberry-pi.
I'd recommend looking at this post (Raspberry Pi- GPIO Events in Python) on the Raspberry Pi SO. That solution shows how to use events so you don't have to run a constant loop - it will just notify you when there is a change.
Related
I'm trying to create an application that will sense my laundry machine turning on. Then when it's done, i want it to detect that and flash my Hue bulbs. I'm using the SW-420 vibration sensor and Python for this project. I have successfully gotten it to recognize vibration, but unfortunately, it's not what I need. The following is my current code.
#!/usr/bin/python
import RPi.GPIO as GPIO
import time
import subprocess
#GPIO SETUP
channel = 17
GPIO.setmode(GPIO.BCM)
GPIO.setup(channel, GPIO.IN)
def start(channel):
if GPIO.input(channel):
print "Dryer has started!"
time.sleep(1)
else:
print "Dryer has stopped"
time.sleep(1)
#f = open("status", "w") #Used to create light status file
#subprocess.call(["perl", "/home/pi/huepi/huepi", "lights"], stdout=f); # creates status file
#subprocess.call(["perl", "/home/pi/huepi/huepi", "for", "1 3 4 5 6 10 11 12", "do", "blinkonce"]); # blinks hue bulbs
GPIO.add_event_detect(channel, GPIO.BOTH, bouncetime=300) # let us know when the pin goes HIGH or LOW
GPIO.add_event_callback(channel, start) # assign function to GPIO PIN, Run function on change
# infinite loop
while True:
time.sleep(1)
The issue that I'm having is even when the machine is running the sensor registers that it has stopped. I've tried using
GPIO.add_event_detect(channel, GPIO.RISING, bouncetime=300)
and
GPIO.add_event_detect(channel, GPIO.FALLING, bouncetime=300)
both with the same results. I just need it to register that the machine has started then with it stops flash the Hue bulb and wait for the next time the machine starts back up.
I'm using a Perl library called Huepl to interface with but bulbs That section of the code is working fine. If you need any more information I'll be glad to supply. Thank you in advance!
Set started via callback on your first detected vibration. Set a lastShakeTime to now via callback whenever you detect vibration.
In your main loop check if nothing was detected for 60s:
import datetime
# infinite loop
while True:
time.sleep(1)
now = datetime.datetime.now()
if started and (now - lastShakeTime).total_seconds() > 60:
# do something with your oleds
Polling vs. Eventbased:
https://sourceforge.net/p/raspberry-gpio-python/wiki/Inputs/
I've written the following simple program in python in order for the user to test/adjust their sound volume. It uses winsound.Beep() to make a repeating beeping noise until it's interrupted by a msvcrt.kbhit() event, and uses threading to allow input while the winsound.Beep() is going on:
import winsound, threading, msvcrt
class soundThread(threading.Thread):
def __init__(self, threadID, pitch, duration):
threading.Thread.__init__(self)
self.threadID = threadID
self.pitch = pitch
self.duration = duration
def run(self):
soundTone(self.pitch,self.duration)
def soundTone(pitch,duration):
winsound.Beep(pitch,int(duration*1000))
def main():
"""main code module"""
print("The computer will play a beeping tone at a frequency of 440 MHz.")
print("It will continue to do so until you press a key which will cause the")
print("sound to stop and the program to exit. While the tone is sounding")
print("adjust your volume so that you can hear the tone clearly and")
print("comfortably.")
print("")
print("Tone starting now...")
loopBool = True
soundBool = True
i = 0;
while loopBool:
i+=1
# make beeping sound
if soundBool:
beep = soundThread(i,440,2.0)
beep.start()
# stop loop if a key is pressed
if msvcrt.kbhit():
loopBool = False
print("Key press detected. Waiting for sound to stop...")
# don't make new beep thread if current one is still active
if beep.isAlive():
soundBool = False
else:
soundBool = True
print("Sound stopped. Exiting program.")
if __name__ == '__main__':
main()
So the code itself works fine. However aesthetically I don't really like having the winsound.Beep() having to start and stop over and over again, and when a key is pressed the program has to wait for the current Beep() thread to end before the entire program can end. However, I can't think of any way to do it using winsound, and I can't find any other built in modules that allow simple generation of sounds like this.
I saw some very similar questions on this site, but all the solutions required non-standard modules like audiolab or PyMedia, but I'd like to do this using standard modules if possible. Is there some way to have a continuous beep until a keyboard interrupt, without having to install any non-standard modules? If there isn't any way with the basic modules, I'm using the Anaconda python distribution, so I at least have access to numpy and scipy, etc., though I kind of doubt those packages would be helpful here.
There is minor correction to your code.
The method name should be in snake_case:
# don't make new beep thread if current one is still active
if beep.is_alive():
not CamelCase:
# don't make new beep thread if current one is still active
if beep.isAlive():
I'm detecting a touch throuth a ttp223b touch sensor via python on a raspberry pi. It works pretty good but i need to wait for a second after a touch detection to prevent more than one execution so i just added a "time.sleep(1)".
The problem is that i also get multiple outputs, they are just time offset to 1 second, it seems that the routine is triggering multiple times at once.
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(3, GPIO.IN)
while 1:
if GPIO.input(3) == GPIO.HIGH:
print "touched :3"
time.sleep(1)
Any suggestions how i could solve the issue?
add a sentinal
last_update = 0
while 1:
if time.time() - last_update > 1.5 : #1 and a half seconds
if GPIO.input(3) == GPIO.HIGH:
print "touched :3"
this will allow the GPIO to continue flushing so you dont pick up the old press (at least I think im not entirely sure how GPIO buffers work here)
I am trying to make a 'game' while learning about both Python and GPIO on the Raspberry Pi. This is what I have ATM:
while playing == 1:
if (GPIO.input(9) == 0):
GPIO.output(18, GPIO.LOW)
print("Well done!!")
time.sleep(1)
else:
print("Wrong!")
lives = lives - 1
time.sleep(1)
playing = 0
Now, my problem is that the program is hitting the if statement and is going straight to the else (as you would expect), however, I want the program to wait on the first part of the if statement for a second, then go to the else.
Thanks in advance!
Perhaps you could rewrite it like so:
while playing == 1:
for _ in range(10):
if GPIO.input(9) == 0:
GPIO.output(18, GPIO.LOW)
print("Well done!!")
break
time.sleep(0.1)
else:
print("Wrong!")
lives = lives - 1
This polls the GPIO pin ten times 100ms apart. The else is hit if the GPIO pin stays high throughout the ten attempts.
(If you haven't come across Python's for-else construct, see Why does python use 'else' after for and while loops?.)
Alternatively, you could use GPIO module's more advanced features, such as edge detection and callbacks. See the documentation.
I am trying to have a script which I trigger via cron to turn a pin low and high based on a temperature, however.. I have having a couple of problems.
1 - When the script starts and it setsup the GPIO pin, it will either pull the pin high or low (depending on paramater) - there doesn't appear to be a way to tell it not to change the current state of the pin.
This is a problem because if the relay is high and the default state is low then the relay will be set low and then could change to high again very quickly after - doing this every minute is pretty hard on what the pin is controlling (same applies if the default state is high).
2 - When the script exits it cleans up the GPIO pins and changes the state of my pin. Ideally if the script turns the pin high then when it exits I want the pin to remain high. If I remove the cleanup function then the next time the script runs it says that the pin was already in use (problem?).
So the script which runs every minute looks like this.
#!/usr/bin/python
import RPi.GPIO as GPIO
import time
import random
from temp import Temp # custom object to handle the temp sensor.
def main():
random.seed()
GPIO.setmode(GPIO.BCM)
PUMP_ON_TEMP = 38
PUMP_OFF_TEMP = 30
GPIO_PIN = 18
try:
t = Temp('28-00000168c492')
GPIO.setup(GPIO_PIN, GPIO.OUT)
current_temp = t.getTemp()
print current_temp
if current_temp > PUMP_ON_TEMP:
GPIO.output(GPIO_PIN, 1)
print "Turning the pump on! %s" % current_temp
if current_temp < PUMP_OFF_TEMP:
GPIO.output(GPIO_PIN, 0)
print "Turning the pump off! %s" % current_temp
except KeyboardInterrupt:
pass
finally:
GPIO.cleanup()
if __name__ == '__main__':
main()
This run every minute via cron. I don't want to use a loop.
I have tried to read the pin as an input first to get current hight/low state but that throws an error saying the pin needs to be setup first....