Search code examples
pythonraspberry-pigpiowebiopi

Raspberry Pi Python pause a loop sequence, when button pushed


I have a raspberry PI 2. With a relay board, what i use to for a switch sequence (like a traffic light). I use a tool, called "webiopi" what create buttons on a website. When the button is clicked the function of the python script below is started.

What i want is to break out of the loop (or pause it) when another button is clicked. However, as long this loop is running, the tool don't look at the webpage

A kind of similar question is asked here Exiting a continuous loop in python via webiopi but this is for a single event and the solution doesn't work in my case.

Question is. How can I make this script look at a button what is clicked (can be a gpio switch as well) while the loop is running

GPIO_nek=11 
GPIO_schouder=12
GPIO_rug1=8
GPIO_ONOFF=18
interval1 = 2
interval2 = 4
for x in range(0, 20):
    GPIO.digitalWrite(GPIO_nek, GPIO.LOW)
    time.sleep(interval1)
    GPIO.digitalWrite(GPIO_schouder, GPIO.LOW)
    time.sleep(interval1)
    GPIO.digitalWrite(GPIO_nek, GPIO.HIGH)
    time.sleep(interval1)
    GPIO.digitalWrite(GPIO_rug1, GPIO.LOW)
    time.sleep(interval2)
    GPIO.digitalWrite(GPIO_schouder, GPIO.HIGH)
    if (GPIO.digitalRead(GPIO_ONOFF) == GPIO.LOW):
        GPIO.digitalWrite(GPIO_ONOFF, GPIO.HIGH)
        break

Solution

  • If the button is the GPIO switch as you mentioned at the end of the question, instead of the webpage button, then you can make use of an inbuilt GPIO interrupt function that saves your computer the resouces of constant polling:

    import RPi.GPIO as GPIO
    from threading import Event  # We'll use it like time.sleep, but we can interrupt it.
    GPIO_nek=11 
    GPIO_schouder=12
    GPIO_rug1=8
    GPIO_ONOFF=18
    interval1 = 2
    interval2 = 4
    GPIO.setup(GPIO_ONOFF, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    
    done = False  # loop control
    timer = Event()
    def quit_loop():  # Called by inbuilt threaded interrupt
        global done
        done = True
        timer.set()  # Interrupt the waiting
    
    GPIO.add_event_detect(GPIO_ONOFF, GPIO.FALLING, callback=quit_loop, bouncetime=300) # Setup interrupt to call quit_loop
    

    Because you're using this to break out of a loop, you want to shorten that loop to a single process:

    tasks = [
    (GPIO_nek, GPIO.LOW, interval1),
    (GPIO_schouder, GPIO.LOW, interval1),
    (GPIO_nek, GPIO.HIGH, interval1),
    (GPIO_rug1, GPIO.LOW, interval2),
    (GPIO_schouder, GPIO.HIGH, 0) ]
    
    for pin, level, interval in tasks * 20:  # Above you ran it 20 times, this notation keeps it in a single loop to break our o
        if not done:
            GPIO.digitalWrite(pin, level)
            timer.wait(interval)
        else:
            timer.clear()
            break
    

    By using the threading Event().wait() and .set() instead of the standard time.sleep() you won't even have to wait for the sleep interval to finish.