ltb76
Posts: 2
Joined: Thu Dec 12, 2019 12:11 pm

Webinterface - FLASK and while loop

Thu Dec 12, 2019 1:04 pm

Hi,

My kid has been bugging me for a "Traffic light" in his room for a while. So when I stumbled upon an old traffic light on the local flea-market I thought it could be a fun project.
I have now hacked it together with a piZero and a relay. Besides a few powershell scripts I'm no programmer - this my my first fun with python.

My first step was to control the relay via python - I found several good scripts and hacked this together:

Code: Select all

#!/usr/bin/python
import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
pinList = [2, 3, 4]

#initialize
for i in pinList:
    GPIO.setup(i, GPIO.OUT)
    GPIO.output(i, GPIO.HIGH)
#time variables

SleepTimeL = 2
SleepTime5 = 5
SleepTime10 = 10

state = True

#traffic light loop
try:
 while True:
  GPIO.output(2, GPIO.LOW)
  print ("Red-ON")
  time.sleep(SleepTime10);

  GPIO.output(3, GPIO.LOW)
  print ("Yellow-ON")
  time.sleep(SleepTime5);

  GPIO.output(2, GPIO.HIGH)
  GPIO.output(3, GPIO.HIGH)
  print ("Red_Yellow-OFF")

  GPIO.output(4, GPIO.LOW)
  print ("Green-ON")
  time.sleep(SleepTime10);

  GPIO.output(3, GPIO.LOW)
  print ("Yellow-ON")
  GPIO.output(4, GPIO.HIGH)
  print ("Green-OFF")
  time.sleep(SleepTime5);

  GPIO.output(3, GPIO.HIGH)
  print ("Yellow-OF")


#Cleanup - clean exit with keyboard interupt
except KeyboardInterrupt:
  print ("  Quit")
  GPIO.cleanup()
First I just fired the script via crontab at reboot. Worked like a charm.

Then the kid bugged me to be able start and top it. I then created a button on my sons tablet, when pressed it silently SSHs into the pi, executes the python script in a "screen session" and then exits. And another button to shoot down the script.

Now he would like to control the lights individually - sigh...
I was then thinking of doing a web interface - how hard could it be :)
So again I found a few projects using python, FLASK and nginx and tried getting it running.

My app.py looks like this:

Code: Select all

from flask import Flask, render_template
import RPi.GPIO as GPIO
import time
#import threading
#import logging

app = Flask(__name__)

GPIO.setmode (GPIO.BCM)

pinList = [2, 3, 4, 17, 9]

for i in pinList:
    GPIO.setup(i, GPIO.OUT)
    GPIO.output(i, GPIO.HIGH)

SleepTime2 = 0.2
SleepTime5 = 0.5
SleepTime10 = 0.10

light_on = False

#default route, without anything
def default():
        # read pin state
        #pin = GPIO.input(2)
        return render_template ('lights.html')

# set a route for action
@app.route("/<status>")
def onAction(status):
        if status == "off":
                print ("All Lights Off")
                light_on = False
                for i in pinList:
                        GPIO.output(i, GPIO.HIGH)
        if status == "red":
                print ("Blink - Red")
                GPIO.output(2, GPIO.LOW)
                time.sleep(SleepTime5);
                GPIO.output(2, GPIO.HIGH)
        if status == "yellow":
                print ("Blink - Yellow")                        
                GPIO.output(3, GPIO.LOW)                
                time.sleep(SleepTime5);                
                GPIO.output(3, GPIO.HIGH)
        if status == "green":
                print ("Blink - Green")                        
                GPIO.output(4, GPIO.LOW)                
                time.sleep(SleepTime5);                
                GPIO.output(4, GPIO.HIGH)
        if status == "blink":
                global light_on
                while light_on:
                        GPIO.output(2, GPIO.LOW)
                        print ("blinking red")
                        time.sleep(SleepTime2);
                        GPIO.output(2, GPIO.HIGH)
                        time.sleep(SleepTime2);
                        return render_template ('lights.html')
                        print("Running trafficsignal")
        
        return render_template ('lights.html')

if __name__ == "__main__":
        app.run(host='0.0.0.0', port=8080, debug=True)

Now the individual "buttons" work (red, yellow, greeen). But my blink button does not work. I assume it is the while loop that is not working.
Any hints would much appreciated.

And my apologies if the code is a mess :)

Thank you in advance.

User avatar
paddyg
Posts: 2463
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: Webinterface - FLASK and while loop

Fri Dec 13, 2019 6:16 pm

Do you need to set the global light_on True? You might need to put your actions into functions and run them in threads to stop the whole thing getting stuck in a flashing light loop. I think you have to put global as the first line of the function. Finally I think you can pass a list to gpio.setup so you don't need that loop

PS has something gone wrong with your indents at the end of the flash loop?
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

ltb76
Posts: 2
Joined: Thu Dec 12, 2019 12:11 pm

Re: Webinterface - FLASK and while loop

Mon Dec 16, 2019 7:14 am

So I got it working. Now the code just needs to be tweaked and cleaned up.

Basically I created a baggrund thread to control the traffic light.

Bagground thread:

Code: Select all

#!/usr/bin/python
import os
from os import path
import RPi.GPIO as GPIO
import time

def threaded_task(traffic):
 GPIO.setmode(GPIO.BCM)
 print ("Traffic controller startet from: " + traffic + "...")
# init list with pin numbers

 pinList = [2, 3, 4]

# loop through pins and set mode and state to 'low'

 for i in pinList:
     GPIO.setup(i, GPIO.OUT)
     GPIO.output(i, GPIO.HIGH)

# time to sleep between operations in the main loop

 SleepTime2 = 2
 SleepTime5 = 5
 SleepTime10 = 10

 state = True

# main loop
 try:
  while True:
   time.sleep(0.5);
   print ("Trafficcontroller is running")
   while os.path.exists('/home/pi/relay/test.txt'):
    #GPIO.output(2, GPIO.LOW)
    print ("Running the traffic sequenze...")
    GPIO.output(2, GPIO.LOW)
    print ("Red-ON")
    time.sleep(4);

    GPIO.output(3, GPIO.LOW)
    print ("Yellow-ON")
    time.sleep(2);
 
    GPIO.output(2, GPIO.HIGH)
    GPIO.output(3, GPIO.HIGH)
    print ("Red_Yellow-OFF")

    GPIO.output(4, GPIO.LOW)
    print ("Green-ON")
    time.sleep(4);

    GPIO.output(3, GPIO.LOW)
    print ("Yellow-ON")
    GPIO.output(4, GPIO.HIGH)
    print ("Green-OFF")
    time.sleep(2);

    GPIO.output(3, GPIO.HIGH)
    print ("Yellow-OFF")
 # GPIO.output(17, GPIO.HIGH)

#  GPIO.cleanup()
#  print ("Good bye!")
#End program cleanly with keyboard
 except KeyboardInterrupt:
   print ("  Quit")
   GPIO.cleanup()
The background thread is controlled from the main app.

Code: Select all

from flask import Flask, render_template
import RPi.GPIO as GPIO
import os
from os import path
from threading import Thread
from traffic import threaded_task

app = Flask(__name__)

pinList = [2, 3, 4, 17]
relay_pin = 17

#pin state
pin = 1

if os.path.exists('/home/pi/relay/test.txt'):
 os.remove('/home/pi/relay/test.txt')
 #os.mknod('/home/pi/relay/test.txt')

GPIO.setmode (GPIO.BCM)
for i in pinList:
 GPIO.setup(i, GPIO.OUT)
 GPIO.output(i, GPIO.HIGH)


#GPIO.setup (relay_pin, GPIO.OUT)
        
thread = Thread(target=threaded_task, args=("app01",))
thread.daemon = True
thread.start()

#default route, without anything
@app.route("/")
def default():
        # read pin state
        pin = GPIO.input(relay_pin)
        return render_template ('lights.html',pin=pin)


# set a route for action
# light on or off
@app.route("/<status>")
def onAction(status):
        pin = 2
        if status == "on":
                pin = 0
                GPIO.output (relay_pin, GPIO.LOW)
                if not os.path.exists('/home/pi/relay/test.txt'):
                        os.mknod('/home/pi/relay/test.txt')
                #message =  "Light on!"
                print ("on")
        if status == "off":
                pin = 1
                if os.path.exists('/home/pi/relay/test.txt'):
                        os.remove('/home/pi/relay/test.txt')
                for i in pinList:
                        GPIO.output(i, GPIO.HIGH)   
                #message = "Light off!"
                print ("off")
        if status == "red-on":
                pin = 0
                if os.path.exists('/home/pi/relay/test.txt'):
                        os.remove('/home/pi/relay/test.txt')
                GPIO.output (17, GPIO.HIGH)
                GPIO.output(2, GPIO.LOW)
                print ("red is on")

        
        # return to the template with new info
        return render_template ('lights.html',pin=pin)

if __name__ == "__main__":
        app.run(host='0.0.0.0', port=8080, debug=True)

When pressing the "run" button it will create a "test.txt" file - and the bagground thread is looking for that.
It might not be pretty - but it works :)

PS: I based my script on this project (https://github.com/feiticeir0/lightup) - that gave me the framework :)

Return to “Python”