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....
Related
I am currently trying to write a python (2.7) script based around the GPSd library to provide GPS speed data at an update rate of 10Hz using the adafruit Ultimate GPS raspberry Pi Hat (https://www.adafruit.com/product/2324) with time stamps also reported at 0.1s.
The module itself is capable of up to 10Hz update rates however defaults to 1 Hz when set up and currently I cannot successfully increase it. I've have tried issuing PMTK commands (https://cdn-shop.adafruit.com/datasheets/PMTK_A11.pdf) to increase the update rate however cannot get this to work (PMTK220) and have included setting the baudrate to the maximum value of 115200.
I've searched all over for a method of getting the update rate output to increase however cannot see where the issue lies. The code below and prints out responses at a rate faster than 10 Hz however the values are only being updated every 1s.
import os
import serial
from gps import *
import datetime
import time
import threading
import subprocess
#### CURRENTLY TRYING TO INCREASE GPS POLLING UPDATE RATE FROM DEFAULT 1Hz to 10Hz
subprocess.call(["stty","-F","/dev/serial0","raw","115200","cs8","clocal","-cstopb"])
subprocess.call(["sudo","systemctl","stop","gpsd.socket"])
subprocess.call(["sudo","systemctl","disable","gpsd.socket"])
subprocess.call(["sudo","gpsd","/dev/ttyS0","-F","/var/run/gpsd.sock"])
subprocess.call(["echo","-e","$PMTK251,115200*27\r\n","/dev/ttyS0"]) # command to set baudrate of serial port
subprocess.call(["echo","-e","$PMTK220,100*2F\r\n","/dev/ttyS0"]) #command to set GPS Update Rate
gpsd = None #seting the global variable
os.system('clear') #clear the terminal (optional)
class GpsPoller(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
global gpsd #bring it in scope
gpsd = gps(mode=WATCH_ENABLE) #starting the stream of info
self.current_value = None
self.running = True #setting the thread running to true
def run(self):
global gpsd
while gpsp.running:
gpsd.next() #this will continue to loop and grab EACH set of gpsd info to clear the buffer
gpsp = GpsPoller() # create the thread
gpsp.start() # start it up
os.system('clear')
x = 0
while x < 20: # infinite loop- use ctrl + c to end
print gpsd.utc # print timestamp
print gpsd.fix.speed # print gps speed
print '-----------------'
time.sleep(0.025) # Set print rate much higher than maximum possible of 10 Hz update rate
Probably a little late for this, but the module is set to a 9600 rate by default, iirc. Try setting the baud to 9600 on the Pi first then send the $PMTK251,115200 line. Now change the rate on the Pi to 115200 & send the 10hz part ($PMTK220,100*2F\r\n)
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/
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.
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 new to python with the Raspberry Pi. Below is a example program to use the GPIO. My problem is that in my conditional I cannot see to have any variables span to other statements in the block
The entire program is included the example of the problem code is as follows:
Turn on GPIO pin 23
print uptime
NameError: global name 'uptime' is not defined
Any suggestions?
Thank in advance
**************************** python code *****************************************
!/usr/bin/env python2.7
import time;
import RPi.GPIO as GPIO
from time import sleep # this lets us have a time delay (see line 12)
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM) # set up BCM GPIO numbering
GPIO.setup(17, GPIO.IN) # set GPIO17 as input (button)
GPIO.setup(23, GPIO.OUT) ## Setup GPIO Pin 23 to OUT
GPIO.output(23,False) ## Turn off GPIO pin 23
Define a threaded callback function to run in another thread when events are detected
def my_callback(channel):
global start_time, uptime
if GPIO.input(17): # if port 17 == 1
end_time = time.time()
#print (end_time)
print "Rising edge detected on 17"
uptime = end_time - start_time
#uptime = int(uptime)
print uptime
GPIO.output(23,False)
## Turn off GPIO pin 2
elif (GPIO.input(17)== 0):
start_time = time.time()
#print (start_time)
print "Falling edge detected on 17"
GPIO.output(23,True)
## Turn on GPIO pin 23
print uptime
when a changing edge is detected on port 17, regardless of whatever
else is happening in the program, the function my_callback will be run
GPIO.add_event_detect(17, GPIO.BOTH, callback=my_callback)
raw_input("Press Enter when ready\n>")
try:
print "When pressed, you'll see: Rising Edge detected on 17"
print "When released, you'll see: Falling Edge detected on 17"
sleep(10) # wait 30 seconds
print "Time's up. Finished!"
print uptime
finally: # this block will run no matter how the try block exits
GPIO.cleanup() # clean up after yourself
If, the first time my_callback gets called, GPIO.input(17) is 1, then you'll set uptime and everything will be fine.
But what happens if the first time it's called, GPIO.input(17) is 0? Then you won't set uptime. And, because this is the first time you've ever called this function, and you don't have any other code that sets uptime, it hasn't been set yet. But you try to print it anyway. So you get a NameError.
You could fix this by, e.g., setting it to an initial value at the start of the problem—e.g.:
def my_callback(channel):
# your existing code
uptime = 0
Of course I'm assuming some reasonable indentation for your code. As pasted, your code is just a mess of IndentationError exceptions and won't do anything, and it's quite possible that your real code has other bugs caused by code not being indented under the right flow control statement.
And, since it looks like you may be mixing tabs and spaces, making indentation errors hard to spot: Get yourself a better text editor, which automatically converts tabs into spaces, auto-indents for you, and/or shows tabs in some visible way. Or at least run your code with the -tt flag to catch tabs as errors so you can fix them.
As a side note, your elif is definitely wasteful, and possibly even broken.
If the if GPIO.input(17): part didn't trigger, then you know the result is 0 (or something else falsey, but since input only returns numbers, it can only be 0). So, why test it again for 0 when it can't be anything else?
But meanwhile, you're not just re-testing a value here unnecessarily, you're actually going out and reading the value again off the hardware. So, if the edge changes from 1 to 0 and back to 1 quickly enough, your first read may return 0, then your second read may return 1, meaning neither of your branches fires. (Plus, by reading, you may have also absorbed the edge trigger so you don't get another callback, although I'm not sure about that.)
You can solve all of these problems by just using else: instead of trying to write an elif that exactly captures the opposite sense of the if.