Flask - 通过网页调用和停止函数 (raspberry pi)

Flask - Calling and stopping functions via webpage (raspberry pi)

我正在尝试设置一个简单的 flask 网页来控制 运行 在 raspberry pi 上的 3d 圣诞树 运行。我已经发布了应用程序的代码和下面的模板。到目前为止,它的工作原理是我可以 运行 一个单一的功能,例如 Flicker,然后执行 Reset 或 Off 功能。但是,之后我无法调用其他函数。如果我 运行 闪烁,然后是随机或全闪,它们就会混合在一起。我的目标是能够通过重置或关闭功能完全停止 GPIO 输出,并通过网页的按钮或链接调用每个相应的功能。

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>

我对如何按预期工作有点迷茫。我读过与线程和多线程相关的类似帖子,但我认为这不是问题所在。我不确定我是否错误地获取和发布了呼叫。我在模板中使用 ajax 阅读过类似的帖子,但我认为这也不是问题,因为 工作 但可能效率不高。

感谢任何帮助、见解或指导。

您好,我没有您的设置,所以无法进行全面测试。但我认为你想要一个后台循环,并使用全局状态来管理与树的交互(因为实际上只有一棵树。)

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)

注意新的 POST 端点:

<!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>