Reputation: 115
I'm trying to setup a simple flask webpage to control a 3d Xmas Tree running on a raspberry pi. I've posted the code for the app and the template below. So far it works in that I can run a single function, such as Flicker and then perform either the Reset or Off functions. However, I am not able to call other functions following that. And if I run Flicker and then Random or All Flash they kind of blend together. My goal is to be able to cleanly stop GPIO output via the reset or off functions and call each respective function via the webpage's buttons or links.
app2.py
import RPi.GPIO as GPIO
import random
from random import randint
from gpiozero.tools import random_values
from flask import Flask, render_template, request
from gpiozero import LEDBoard
from time import sleep
from signal import pause
app = Flask(__name__)
GPIO.setmode(GPIO.BCM)
tree = LEDBoard(*range(2,28),pwm=True)
@app.route("/")
def home2():
return render_template("home2.html")
@app.route("/flicker/", methods=['POST', 'GET'])
def flicker():
# GPIO.cleanup()
for led in tree:
led.source_delay = random.uniform(0.1, 0.9)
led.source = random_values()
sleep(1)
pause()
return render_template("home2.html")
@app.route("/randomOnOff/", methods=['POST', 'GET'])
def randomOnOff():
while True:
for led in tree:
s = randint(0,1)
if (s==1):
led.on()
else:
led.off()
sleep(1)
return render_template("home2.html")
@app.route("/allFlash/", methods=['POST', 'GET'])
def allFlash():
while True:
tree.on()
sleep(1)
tree.off()
sleep(1)
return render_template("home2.html")
@app.route("/upAndDown/", methods=['POST', 'GET'])
def upAndDown():
while True:
tree.off()
order = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,0]
for item in order:
tree[item].on()
sleep(0.1)
order.reverse()
sleep(0.5)
for item in order:
tree[item].off()
sleep(0.1)
return render_template("home2.html")
@app.route("/reset/", methods=['POST', 'GET'])
def tree_reset():
GPIO.cleanup()
return render_template("home2.html")
@app.route("/off/", methods=['POST', 'GET'])
def tree_off():
tree.off()
return render_template("home2.html")
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5000, debug=True)
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Raspberry Pi Xmas Tree</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
</head>
<body>
<header>
<div class="container">
<h1 class="logo">Raspberry Pi Christmas Tree</h1>
<strong><nav>
<a href="/" class="button">Home</a>
<br/>
<br/>
<ul class="menu">
<form action="/flicker/" method="post">
<button name="flicker" type="submit">Flicker Lights</button>
</form>
<br/>
<form action="/randomOnOff/" method="post">
<button name="randomOnOff" type="submit">Random Lights</button>
</form>
<br/>
<form action="/allFlash/" method="post">
<button name="allFlash" type="submit">Flash All Lights</button>
</form>
<br/>
<form action="/upAndDown/" method="post">
<button name="upAndDown" type="submit">Up and Down</button>
</form>
<br/>
<form action="/reset/" method="post">
<button name="reset" type="submit">Reset</button>
</form>
<br/>
<form action="/off/" method="post">
<button name="off" type="submit">Turn Off</button>
</form>
</ul>
</nav></strong>
</div>
</header>
{% block content %}
{% endblock %}
</body>
</html>
I'm a little lost on getting this working as intended. I've read into similar posts related to threading and multi-threading, but I don't think that is the issue. I am not sure if I am GETting and POSTing the calls incorrectly. I've read similar posts using ajax in the template, but I don't think that is an issue either as this does work but possibly not efficiently.
Any help, insight, or guidance is appreciated.
Upvotes: 1
Views: 419
Reputation: 318
Hi I don't have your setup so I couldn't test fully. But I think you want a background loop, and use global state to manage interaction with tree (since there is physically one tree.)
from enum import Enum
from random import randint, uniform
from threading import Thread
from time import sleep
from flask import Flask, render_template, request, redirect, url_for
from gpiozero import LEDBoard
from gpiozero.tools import random_values
import RPi.GPIO as GPIO
class TreeState(Enum):
OFF = 1
FLICKER = 2
RANDOM_ON_OFF = 3
ALL_FLASH = 4
UP_AND_DOWN = 5
TERMINATE = 6
def main_loop():
while True:
if state == TreeState.TERMINATE:
tree.off()
GPIO.cleanup()
quit()
if state == TreeState.ALL_FLASH:
tree.on()
sleep(1)
tree.off()
# to prevent you could set looping state = TreeState.OFF
# state = TreeState.OFF
if state == TreeState.RANDOM_ON_OFF:
tree.off()
for led in tree:
s = randint(0,1)
if s == 1:
led.on()
else:
led.off()
# state = TreeState.OFF
if state == TreeState.UP_AND_DOWN:
tree.off()
order = list(range(1, 25)) + [0]
for item in order:
tree[item].on()
sleep(0.1)
order.reverse()
sleep(0.5)
for item in order:
tree[item].off()
sleep(0.1)
# state = TreeState.OFF
# I have been unable to test this
if state == TreeState.FLICKER:
for led in tree:
led.source_delay = random.uniform(0.1, 0.9)
led.source = random_values()
sleep(1)
# after a second repeat the loop
sleep(1)
app = Flask(__name__)
state = TreeState.OFF
GPIO.setmode(GPIO.BCM)
tree = LEDBoard(*range(2, 28), pwm=True)
@app.route("/")
def home2():
return render_template("home2.html", state=str(state))
# post-redirect-get
@app.route("/setState/<new_state>", methods=["POST"])
def setState(new_state):
new_state = TreeState[new_state]
global state
state = new_state
return redirect(url_for('home2'))
if __name__ == "__main__":
Thread(name="backgroundLoop", target=main_loop).start()
app.run(host='0.0.0.0', port=5000, debug=True)
Note new POST endpoints:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Raspberry Pi Xmas Tree</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
</head>
<body>
<header>
<div class="container">
<h1 class="logo">Raspberry Pi Christmas Tree</h1>
<h2 class="status">The tree is {{state}}</h2>
<strong><nav>
<a href="/" class="button">Home</a>
<br/>
<br/>
<ul class="menu">
<form action="/setState/FLICKER" method="post">
<button name="flicker" type="submit">Flicker Lights</button>
</form>
<br/>
<form action="/setState/RANDOM_ON_OFF" method="post">
<button name="randomOnOff" type="submit">Random Lights</button>
</form>
<br/>
<form action="/setState/ALL_FLASH" method="post">
<button name="allFlash" type="submit">Flash All Lights</button>
</form>
<br/>
<form action="/setState/UP_AND_DOWN" method="post">
<button name="upAndDown" type="submit">Up and Down</button>
</form>
<br/>
<form action="/setState/OFF" method="post">
<button name="reset" type="submit">Reset</button>
</form>
<br/>
<form action="/setState/TERMINATE" method="post">
<button name="off" type="submit">Shut down server</button>
</form>
</ul>
</nav></strong>
</div>
</header>
{% block content %}
{% endblock %}
</body>
</html>
Upvotes: 1