Python Don't Repeat Consecutive Lines - python

I am writing a python script, that will show the status of a raspberry pi's gpio input pins in a web browser. This script is just for the backend testing:
import RPi.GPIO as GPIO
import time
import os
os.system('clear')
GPIO.setmode(GPIO.BOARD)
GPIO.setup(29, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(32, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(37, GPIO.IN, pull_up_down=GPIO.PUD_UP)
while True:
input_state = GPIO.input(37)
if input_state == False:
print('One')
time.sleep(0.2)
input_state = GPIO.input(32)
if input_state == False:
print('Two')
time.sleep(0.2)
input_state = GPIO.input(29)
if input_state == False:
print('Three')
time.sleep(.02)
My output crazily spams the screen with the number until the input switch is turned off. How can I prevent the same consecutive line from repeating immediately?
Thanks!

How about printing only when the input states actually change? Something like this (untested):
# Your code to initialise everything:
import RPi.GPIO as GPIO
import time
import os
os.system('clear')
GPIO.setmode(GPIO.BOARD)
GPIO.setup(29, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(32, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(37, GPIO.IN, pull_up_down=GPIO.PUD_UP)
# New loop keeping track of the previous ("old") input states:
old_input_states = [None] * 3
while True:
input_states = [GPIO.input(n) for n in (37, 32, 29)]
if input_states != old_input_states:
for n, name in enumerate(['One', 'Two', 'Three']):
if input_states[n] == False:
print name
old_input_states = input_states
So to explain what this new loop code is doing:
First, a list old_input_states is created which contains three None entries. This will be used to remember the last state of the three GPIOs.
Then at the beginning of the loop, the GPIO.input(n) function is called, for n being 37, 32 and 29 for the three GPIOs. The resulting list input_states now contains the three GPIO states.
Then this list is compared against the old_input_states list and if they differ, it will do the following:
For each name in 'One', 'Two' and 'Three' (which are enumerated by n, i.e. for 'One' it is 0, 1 for 'Two' and 2 for 'Three'), it checks the value of that input_states[n] to see if it is False and if it is, it prints the name which should match the corresponding GPIO.
Then it updates old_input_states to match input_states so in the next loop, it will only check (and potentially print) again if the input_states changed.
EDIT
Note that the code will output all GPIOs which are currently False at the point where a change is detected. To only print the ones going from True to False, you should be able to use the following code for the section starting with the # New loop comment:
# New loop keeping track of the previous ("old") input states:
old_input_states = [None] * 3
while True:
input_states = [GPIO.input(n) for n in (37, 32, 29)]
for n, name in enumerate(['One', 'Two', 'Three']):
if input_states[n] != old_input_states[n] and input_states[n] == False:
print name
old_input_states = input_states
EDIT 2
As indicated by the OP, the preferred output is in list-form anyway. Also there appeared to be some bouncing happening on the switch inputs to the GPIOs, which could be improved by using the time.sleep calls. Further, the output should be inverted. The final code of the while loop looks like this:
old_input_states = [None] * 3
while True:
input_states = [GPIO.input(n) for n in (37, 32, 29)]
if input_states != old_input_states:
inverted_input_states = [1 - i for i in input_states]
print inverted_input_states
time.sleep(0.2)
old_input_states = input_states
Disclaimer: For better debouncing reliability of switches I'd use different code, but that is beyond the scope of this question

You could modify your code to work with an 'on change' type logic:
import RPi.GPIO as GPIO
import time
import os
os.system('clear')
GPIO.setmode(GPIO.BOARD)
# allows you to rename the io ports
io_names = [ 'One', 'Two', 'Three' ]
class IOMonitor():
def __init__( self, num , io, pud ):
self.num = num
GPIO.setup(self.num, io, pull_up_down=pud)
self.last_state = GPIO.input(self.num)
def poll( self ):
# detect current state
current_state = GPIO.input(self.num)
# compare with old state
if( current_state != self.last_state ):
# set new last state
self.last_state = current_state
# print name of io that changed
print( io_names[self.num] )
ioMonitors = [
IOMonitor(29, GPIO.IN, GPIO.PUD_UP),
IOMonitor(32, GPIO.IN, GPIO.PUD_UP),
IOMonitor(37, GPIO.IN, GPIO.PUD_UP)
]
def main():
while True:
for io in ioMonitors:
io.poll()
time.sleep(0.2)
main()
I don't have access to your libraries so this code is untested but should be logically correct.

Related

Using If statement in python comparing time to a value

I am trying to write a simple code in python which working on the Raspberry pi.
This code is working but I want to make a better code when I turb on LED in different time.
such as 5minutes later turn on the first led and another 5minutes later second led ....
The problem is when I changing the dlay time such as 5minutes or 10minutes, I have to do hard coding and it seems not a good way to do.
I also tried to adding time to timeset but could not find out the solution.
import RPi.GPIO as GPIO
from datetime import datetime
from datetime import timedelta
import time
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(24, GPIO.OUT)
GPIO.setup(6, GPIO.OUT)
GPIO.setup(5, GPIO.OUT)
try:
while True:
timeset = datetime.now().strftime("%H:%M:%S")
print(timeset)
time.sleep(5)
if timeset > "19:11":
GPIO.output(24, True)
print('Please take a medicine')
if timeset > "19:12":
GPIO.output(6, True)
time.sleep(10)
GPIO.output(24, False)
GPIO.output(6, False)
time.sleep(0.30)
#if timeset =="00:23:30":
# timeset = datetime.now() + timedelta(minutes=1)
finally:
print("clean up")
GPIO.cleanup()`
https://discuss.tryton.org/t/typeerror-unsupported-operand-type-s-for-int-and-datetime-timedelta/4966
I have looked this and tried applying on my code but does not work.
You could go with a basic state machine.
Keep just sleep periods. No need anymore to deal with dates.
Example :
import time
i = 0
state = 0
while True:
time.sleep(5)
state = i%3
if state == 0:
print("light on led A")
elif state == 1:
print("light on led B")
elif state == 2:
print("light on led C")
i += 1
i increments forever
At each loop iteration thanks to the modulo function, state changes value in a cyclic way : 0, 1, 2, 0, 1, 2, ...
For each state value it's up to you to do whatever you decide with the RPi leds.

Blinking led script with GPIO LEDS

I've been starting to learn Python on my raspberry pi.
I have 5 LEDs on GPIO pin 8, 10, 12, 16 and 18.
I have another code working, but I was trying to make it more compact. This one is not working but you can probably guess what I was trying to do.
I'm trying to make each led blink one by one by cycling through the chan_list list, but I'm stuck. How do I repeat the function for each entry of the list?
import RPi.GPIO as GPIO
from time import sleep
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
chan_list = [8,10,12,16,18]
GPIO.setup(chan_list, GPIO.OUT, initial=0)
delay = 50
#delay = float(input("50-1000ms"))
delay = delay / 1000
led = 0
while True:
def blink():
GPIO.output(chan_list, 1)
sleep(delay)
GPIO.output(chan_list, 0)
sleep(delay)
blink()
You can use the itertools.cycle() function to create an iterator that will — wait for it! — cycle through the values is the list.
This means something like this ought to work (I can't test it). Note I also moved the definition of blink() out of the loop — there's no need to do it more than once.
from itertools import cycle # ADDED.
from time import sleep
import RPi.GPIO as GPIO
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
chan_list = [8,10,12,16,18]
chan_cycler = cycle(chan_list) # ADDED.
GPIO.setup(chan_list, GPIO.OUT, initial=0)
delay = 50
#delay = float(input("50-1000ms"))
delay = delay / 1000
delay = 1
led = 0
def blink():
chan = next(chan_cycler) # ADDED.
GPIO.output(chan, GPIO.HIGH)
sleep(delay)
GPIO.output(chan, GPIO.LOW)
sleep(delay)
while True:
blink()
def blink(): should be defined near the top, not inside of a loop. The GPIO.output() function takes a single pin number as its input, not a list of pins. The same goes for GPIO.setup(). To make things a bit easier, get rid of the function. You don't need it in this specific case. You should use a for loop to go over each element and call GPIO.setup() on it. Then, inside of the while loop, you need another for loop which goes over each of the elements in chan_list and turns them on and off. i don't have a Raspberry Pi on me right now, but I'd bet this would get the job done:
import RPi.GPIO as GPIO
from time import sleep
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
chan_list = [8,10,12,16,18]
for pin_number in chan_list:
GPIO.setup(pin_number, GPIO.OUT, initial=0)
delay = 50
#delay = float(input("50-1000ms"))
delay = delay / 1000
led = 0
while True:
for pin_number in chan_list:
GPIO.output(pin_number, 1)
sleep(delay)
GPIO.output(pin_number, 0)
sleep(delay)

End While-Loop from another IF-Statement

i am building a Phone with my Raspberry Pi and Twinkle.
In my example i am starting Twinkle with a subprocess and checking the output for my code.
Now i need to start a while-loop when someone is calling to check the "end-call button". This works well but i need to end the loop if the far end cancelled the call. How can i break the while loop from another if condition?
Here is my code for example:
#IMPORTS
import sys
import time
import RPi.GPIO as GPIO
from multiprocessing.pool import ThreadPool
import threading
#START TWINKLE
from subprocess import Popen, PIPE
proc = Popen(["twinkle", "-c"], stdin=PIPE, stdout=PIPE, bufsize=1)
for line in iter(proc.stdout.readline, b''):
print line
#BUTTON WATCHER
def button_watch():
input_state = GPIO.input(36)
while (input_state == False):
print "loop"
#END LOOP ON BUTTON PRESS
if (input_state == False):
print('Button Pressed')
input_state = GPIO.input(36)
GPIO.setup(32, GPIO.OUT)
GPIO.output(32, GPIO.LOW)
proc.stdin.write("answer\n")
time.sleep(0.2)
break
#INCOMING CALL
def main():
if (line.find("incoming call") > 0):
print "call is coming"
GPIO.setmode(GPIO.BOARD)
GPIO.setup(32, GPIO.OUT)
GPIO.output(32, GPIO.HIGH)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(36, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#START BUTTON WATCHER ON INCOMING CALL
t1 = threading.Thread(target=button_watch)
t1.start()
#CALL CANCELLED
if (line.find("far end cancelled call") > 0):
print "call was cancelled"
GPIO.setmode(GPIO.BOARD)
GPIO.setup(32, GPIO.OUT)
GPIO.output(32, GPIO.LOW)
##############################################
# NEED TO END WHILE LOOP FROM "button_watch" #
##############################################
tmain = threading.Thread(target=main)
tmain.start()
proc.communicate()
I added a comment seeking clarification because I am not sure I understand the intent completely. Now, eventually you will find better and more robust ways to do this but the simplest solution would be to check for a compound condition (assuming you still need input_condition == False).
So you could define a global flag called remote_disconnected, initialize it in a way that your while loop runs in the beginning, and compound it like:
while (input_condition == False and remote_disconnected == False):
make the button_watch depend on a global flag, so you can turn the flag to False

Combining two python codes for raspberry pi with a servo and ldr sensor

I have Python code running on my raspberry pi 2b and a light sensor, which measures the amount of time it takes for the capacitor of the light sensor to charge and send the pin high:
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
pin_to_circuit = 7
def rc_time (pin_to_circuit):
count = 0
#Output on the pin for
GPIO.setup(pin_to_circuit, GPIO.OUT)
GPIO.output(pin_to_circuit, GPIO.LOW)
time.sleep(0.1)
#Change the pin back to input
GPIO.setup(pin_to_circuit, GPIO.IN)
#Count until the pin goes high
while (GPIO.input(pin_to_circuit) == GPIO.LOW):
count += 1
if count > 1000000:
return True
else:
return count
#Catch when script is interrupted, cleanup correctly
try:
# Main loop
while True:
print rc_time(pin_to_circuit)
except KeyboardInterrupt:
pass
finally:
GPIO.cleanup()
I want when the count goes higher than 1000000, a MG90S, that I have also connected to the pi and a 4AA battery pack, moves about 90 degrees.
The code I was trying to integrate to move the servo:
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT)
p.ChangeDutyCycle(7.5) # turn towards 90 degree
time.sleep(1) # sleep 1 second
p.stop()
GPIO.cleanup()
I want to combine these two Python codes. I tried for a bit, but I have almost no Python experience.
The code is now:
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
pin_to_circuit = 7
def move_90_degrees():
GPIO.setmode(GPIO.BOARD)
GPIO.setup(12, GPIO.OUT)
p = GPIO.PWM(12, 50)
p.start(7.5)
p.ChangeDutyCycle(7.5) # turn towards 90 degree
time.sleep(1) # sleep 1 second
p.stop()
def rc_time (pin_to_circuit):
count = 0
#Output on the pin for
GPIO.setup(pin_to_circuit, GPIO.OUT)
GPIO.output(pin_to_circuit, GPIO.LOW)
time.sleep(0.1)
#Change the pin back to input
GPIO.setup(pin_to_circuit, GPIO.IN)
#Count until the pin goes high
while (GPIO.input(pin_to_circuit) == GPIO.LOW):
count += 1
if count > 1000000:
return True
move_90_degrees()
else:
return count
#Catch when script is interrupted, cleanup correctly
try:
# Main loop
while True:
print rc_time(pin_to_circuit)
except KeyboardInterrupt:
pass
finally:
GPIO.cleanup()
The code does print True when the count exceeds 1000000, but the servo still doesn't move. The servo code on its own does however work correctly. (I forgot a bit of the servo code, that's why p wasn't defined, sorry.)
You could just integrate the code block you are using to move the MG90S into a function, insert it before or below your def rc_time (pin_to_circuit): (but first you have to define p inside, its not really clear what p refers to):
New Function from second code block:
def move_90_degrees():
p = '???'
GPIO.setup(12, GPIO.OUT)
p.ChangeDutyCycle(7.5) # turn towards 90 degree
time.sleep(1) # sleep 1 second
p.stop()
After defining this function, call it inside your first block like:
if count > 1000000:
move_90_degrees()
return True
else:
return count
That should work.
I've made a mistake in the code. I changed the order of the function call inside of the
if count > 1000000:
return True
move_90_degrees()
else:
return count
block to :
if count > 1000000:
move_90_degrees()
return True
else:
return count
otherwise, the code returns before the function call is executed. Is it working now?

QTR-8RC Reflectance Sensor Array not returning data

I purchased a QTR-8RC Reflectance Sensor Array and now trying to configure it with Python. I am trying to determine the rate of decay of the voltage that is being read by my receivers (phototransistors) so that I know when a line is being detected. I don't know why my Python code isn't returning anything. Not even a warning statement. Additional information includes that by default the GPIO is an output and the LEDs are ON. Any help is appreciated!
import RPi.GPIO as GPIO
from time import sleep
def Read():
GPIO.setmode(GPIO.BOARD)
GPIO.setup(5, GPIO.OUT)
sleep(0.01)
count = 0
GPIO.setup(5, GPIO.IN)
while GPIO.input(5) == True:
count = count + 1
return count
while True:
Read()
print(Read())
sleep(1)
I don't have any knowledge about QTR-8RC Reflectance Sensor Array.
But looking at your python code, the problem might be with
while GPIO.input(5) == True
If the value is always true then the line with the return statement is never reached.
You could use print statement after while block to check that. Something like
while GPIO.input(5) == True:
count = count + 1
print "while loop has ended"
return count
Instead of running the program continuously run it for some time and check the outputs.
And may be you need to increase the sleep time to see the output practically.
import RPi.GPIO as GPIO
from time import sleep
def Read():
GPIO.setmode(GPIO.BOARD)
GPIO.setup(5, GPIO.OUT)
sleep(0.01)
count = 0
GPIO.setup(5, GPIO.IN)
while GPIO.input(5) == True:
count = count + 1
print "count :", count
return count
for _ in range(100):
print(Read())
sleep(2)

Categories