Flask 动态改变按钮状态

0 投票
2 回答
4481 浏览
提问于 2025-04-18 09:34

我正在尝试理解Flask是怎么工作的。我跟着这个例子:例子。我可以顺利地启用和禁用系统。文本会根据系统的状态动态变化,但按钮却没有。

我想通过GPIO按钮和网页来启用和禁用系统。现在,如果我在网页上启用系统,然后通过GPIO按钮禁用它,网页上的按钮仍然显示为开启状态,这样我就得再次禁用它,然后再启用。

有没有办法让按钮自动变为开启状态?(不是“系统已启用/禁用”的文本,而是真正的按钮)

我的代码是:

index.html:

<!doctype html>
<head>
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.0/jquery.mobile-1.4.0.min.css" />
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.4.0/jquery.mobile-1.4.0.min.js"></script>
</head>

<style>
h3, h4 {text-align: center;}
span {font-weight: bold;}
</style>

<script type=text/javascript>
    $(
    // When the LED button is pressed (change)
    // do an ajax request to server to change LED state
    function() 
    {
        $('#flip-1').change(function() 
        {
        $.getJSON('/_led', {state: $('#flip-1').val()});
        });     
    }
    );

    $(
    // periodically (500ms) do an ajax request to get the button state
    // modify the span tag to reflect the state (pressed or not)
    // the state text comes from the JSON string returned by the server
    function button() 
    {
        $.getJSON('/_button', function(data)
            {
                $("#buttonState").text(data.buttonState);
                setTimeout(function(){button();},500);
            });
    }
    );


</script>
<!-- Simple JQuery Mobile page that display the button state on the breadoard -->
<!-- You can also change the LED state with the slider switch -->
<!-- The Raspberry Pi uptime is displayed in the footer (Jinja2 expands the template tag) -->

<div data-role="page" data-theme="b">
  <div data-role="header">
    <div><h3>Raspberry Pi Web Control</h3></div>
  </div>

  <div data-role="content">
    <form>
    <p>The system is <span id="buttonState"></span></p>
    <br>
    <select name="flip-1" id="flip-1" data-role="slider" style="float: left;">
        <option value="off">Sys off</option>
        <option value="on">Sys on</option>
    </select>
    </form>
  </div>
 <div data-role="footer">
    <div><h4>This Raspberry Pi has been {{uptime}}</h4></div>
  </div>
</div>

web.py:

from flask import Flask, render_template, request, jsonify
import test
app = Flask(__name__)

# return index page when IP address of RPi is typed in the browser
@app.route("/")
def Index():
    return render_template("index.html", uptime=GetUptime())

# ajax GET call this function to set led state
# depeding on the GET parameter sent
@app.route("/_led")
def _led():
    state = request.args.get('state')
    if state=="on":
        test.arm()
        test.write1()
        print test.read()
    else:
        test.disarm()
        test.write0()
        print test.read()
    return ""

# ajax GET call this function periodically to read button state
# the state is sent back as json data
@app.route("/_button")
def _button():
    if (test.read() == "1"):
        state = "armed"
    else:
        state = "disarmed"
    return jsonify(buttonState=state)

def GetUptime():
    # get uptime from the linux terminal command
    from subprocess import check_output
    output = check_output(["uptime"])
    # return only uptime info
    uptime = output[output.find("up"):output.find("user")-5]
    return uptime

# run the webserver on standard port 80, requires sudo
if __name__ == "__main__":
    test.initialize_Output()
    app.run(host='0.0.0.0', port=80, debug=True)

2 个回答

0

结合Ben的回答和另一行代码,我终于得到了我想要的结果。这个HTML文件里的脚本应该是这样的:

<style>
h3, h4 {text-align: center;}
span {font-weight: bold;}
</style>

<script type=text/javascript>
    $(
    // When the LED button is pressed (change)
    // do an ajax request to server to change LED state
    function() 
    {
        $('#flip-1').change(function() 
        {
        $.getJSON('/_led', {state: $('#flip-1').val()});
        });     
    }
    );

    $(
    // periodically (500ms) do an ajax request to get the button state
    // modify the span tag to reflect the state (pressed or not)
    // the state text comes from the JSON string returned by the server
   function button() 
    {
    $.getJSON('/_button', function(data)
        {
            //Ben's line in order to change the slider's state
            $('#flip-1').val(data.buttonState);
            //The new line that makes the slider work depending on the state's value
            $('#flip-1').slider('refresh');
            $("#buttonState").text(data.buttonState);

            // New line to update button state

            setTimeout(function(){button();},500);
        });
    }
    );
</script>

我不太确定那一行新代码具体是干嘛的,但我猜它只是刷新了滑块的状态,以便获取新的结果。谢谢你的帮助,Ben。我真的很感激。现在我有了一个可靠的解决方案,可以继续添加按钮来实现更多功能。

0

jQuery有一个叫val()的方法,它可以用来获取和设置控件的值(虽然不总是这样,但一般来说是的——想了解更多可以查看http://api.jquery.com/val/)。所以我觉得你只需要用val()来更新flip-1的值,每当你从服务器获取按钮状态的时候。

使用val()方法时,值需要和HTML中select元素里的option元素的value属性匹配。如果HTML中的状态值和Flask代码中的状态值一致,你的代码会简单很多,所以我只是更新了HTML,Flask代码保持不变。

<!doctype html>
<html>
    <head>
        <meta name="viewport" content="initial-scale=1, maximum-scale=1">
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.0/jquery.mobile-1.4.0.min.css" />
        <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
        <script src="http://code.jquery.com/mobile/1.4.0/jquery.mobile-1.4.0.min.js"></script>

        <style>
            h3, h4 {text-align: center;}
            span {font-weight: bold;}
        </style>

        <script type=text/javascript>
            $(function() {
                // When the LED button is pressed (change)
                // do an ajax request to server to change LED state


                $('#flip-1').change(function() {
                    $.getJSON('/_led', {state: $('#flip-1').val()});
                });     


                // periodically (500ms) do an ajax request to get the button state
                // modify the span tag to reflect the state (pressed or not)
                // the state text comes from the JSON string returned by the server
                function button(){
                    var data = ajax_button('/_button');

                    // New line to update button state; and refresh the jQuery mobile slider widget
                    $('#flip-1').val(data.buttonState).slider('refresh');

                    $("#buttonState").text(data.buttonState);
                }

                button(); // Update state on page load
                setInterval(button,500); // And then update every 0.5 seconds after that
            });
        </script>
    </head>

    <body>
        <!-- Simple JQuery Mobile page that display the button state on the breadoard -->
        <!-- You can also change the LED state with the slider switch -->
        <!-- The Raspberry Pi uptime is displayed in the footer (Jinja2 expands the template tag) -->

        <div data-role="page" data-theme="b">
          <div data-role="header">
            <div><h3>Raspberry Pi Web Control</h3></div>
          </div>

          <div data-role="content">
            <form>
            <p>The system is <span id="buttonState"></span></p>
            <br>

            <!-- Changed these option values to match the values returned by Flask -->
            <select name="flip-1" id="flip-1" data-role="slider" style="float: left;">
                <option value="disarmed">Sys off - disarmed</option>
                <option value="armed">Sys on - armed</option>
            </select>
            </form>
          </div>
         <div data-role="footer">
            <div><h4>This Raspberry Pi has been {{uptime}}</h4></div>
          </div>
        </div>
    </body>

</html>

我改了几个地方:

  • 将select元素的选项值从on/off改成armed/disarmed,以匹配Flask的状态值
  • 在HTML中添加了html和body元素
  • 把script和style移动到了head元素里
  • 添加了.val()方法,根据通过AJAX从Flask传来的状态设置select元素的值
  • 把两个JavaScript的$()函数合并成一个函数。$()是jQuery的简写,意思是“在DOM加载完成后执行这段代码”
  • 使用setInterval()代替setTimeout() https://developer.mozilla.org/en-US/docs/Web/API/window.setInterval

这是jsfiddle的链接,如果你想对比的话可以查看 http://jsfiddle.net/LcBQ7/4/

撰写回答