'Countdown timer, how to update variable in Python Flask with HTML?

I'm new to coding in general, my teacher told us to make a countdown timer with physical LEDs and use a webserver (flask) for virtual buttons. I want to show the current time of the timer but I can't seem to make the current time countdown with the LEDs, as it tries to finish the LED code before updating. Count up works as it updates every time I click... This is my flask code:

import RPi.GPIO as GPIO
import time
from flask import Flask, render_template, request

app = Flask(__name__)

GPIO.setmode (GPIO.BCM)
GPIO.setup(5, GPIO.OUT)
GPIO.setup(6, GPIO.OUT)
GPIO.setup(13, GPIO.OUT)
GPIO.setup(19, GPIO.OUT)
GPIO.setup(26, GPIO.OUT)


intRepeat = 0
intCount = 0


@app.route('/')
def index():
    templateData = {
        'intCount' : intCount
    }
    return render_template('index3.html', **templateData)
    
@app.route('/up/')
def up():
    global intCount 
    intCount = intCount + 1
    if intCount == 1:
        GPIO.output(5, GPIO.HIGH)
    elif intCount == 2:
        GPIO.output(6, GPIO.HIGH)
        GPIO.output(5, GPIO.LOW)
    elif intCount == 3:
        GPIO.output(5, GPIO.HIGH)
    elif intCount == 4:
        GPIO.output(5, GPIO.LOW)
        GPIO.output(6, GPIO.LOW)
        GPIO.output(13, GPIO.HIGH)
    elif intCount == 5:
        GPIO.output(5, GPIO.HIGH)
    elif intCount == 6: 
        GPIO.output(5, GPIO.LOW)
        GPIO.output(6, GPIO.HIGH)
    elif intCount == 7:
        GPIO.output(5, GPIO.HIGH)
    elif intCount == 8: 
        GPIO.output(5, GPIO.LOW)
        GPIO.output(6, GPIO.LOW)
        GPIO.output(13, GPIO.LOW)
        GPIO.output(19, GPIO.HIGH)
    elif intCount == 9: 
        GPIO.output(5, GPIO.HIGH)
    elif intCount == 10:
        GPIO.output(5, GPIO.LOW)
        GPIO.output(6, GPIO.HIGH)
    elif intCount == 11:
        GPIO.output(5, GPIO.HIGH)
    elif intCount == 12:
        GPIO.output(5, GPIO.LOW)
        GPIO.output(6, GPIO.LOW)
        GPIO.output(13, GPIO.HIGH)
    elif intCount == 13: 
        GPIO.output(5, GPIO.HIGH)
    elif intCount == 14:
        GPIO.output(5, GPIO.LOW)
        GPIO.output(6, GPIO.HIGH)
    elif intCount == 15:
        GPIO.output(5, GPIO.HIGH)
    elif intCount == 16:
        GPIO.output(5, GPIO.LOW)
        GPIO.output(6, GPIO.LOW)
        GPIO.output(13, GPIO.LOW)
        GPIO.output(19, GPIO.LOW)
        GPIO.output(26, GPIO.HIGH)
    elif intCount == 17: 
        GPIO.output(5, GPIO.HIGH)
    elif intCount == 18:
        GPIO.output(5, GPIO.LOW)
        GPIO.output(6, GPIO.HIGH)
    elif intCount == 19:
        GPIO.output(5, GPIO.HIGH)
    elif intCount == 20:
        GPIO.output(5, GPIO.LOW)
        GPIO.output(6, GPIO.LOW)
        GPIO.output(13, GPIO.HIGH)
    elif intCount == 21:
        GPIO.output(5, GPIO.HIGH)
    elif intCount == 22:
        GPIO.output(5, GPIO.LOW)
        GPIO.output(6, GPIO.HIGH)
    elif intCount == 23:
        GPIO.output(5, GPIO.HIGH)
    elif intCount == 24:
        GPIO.output(5, GPIO.LOW)
        GPIO.output(6, GPIO.LOW)
        GPIO.output(13, GPIO.LOW)
        GPIO.output(19, GPIO.HIGH)
    elif intCount == 25: 
        GPIO.output(5, GPIO.HIGH)
    elif intCount == 26:
        GPIO.output(5, GPIO.LOW)
        GPIO.output(6, GPIO.HIGH)
    elif intCount == 27:
        GPIO.output(5, GPIO.HIGH)
    elif intCount == 28:
        GPIO.output(5, GPIO.LOW)
        GPIO.output(6, GPIO.LOW)
        GPIO.output(13, GPIO.HIGH)
    elif intCount == 29:
        GPIO.output(5, GPIO.HIGH)
    elif intCount == 30:
        GPIO.output(5, GPIO.LOW)
        GPIO.output(6, GPIO.HIGH)
    elif intCount == 31:
        GPIO.output(5, GPIO.HIGH)
    elif intCount == 32:
        intCount = intCount - 1
    templateData = {
        'intCount' : intCount
    }
    return render_template('index3.html', **templateData)
    
@app.route('/down/')
def down():
    global intCount
    while(intCount > 0):
        intCount = intCount - 1
        time.sleep(1) 
        if  intCount == 31:
            GPIO.output(5, GPIO.HIGH)
            GPIO.output(6, GPIO.HIGH)
            GPIO.output(13, GPIO.HIGH)
            GPIO.output(19, GPIO.HIGH)
            GPIO.output(26, GPIO.HIGH)
        elif intCount == 30:
            GPIO.output(5, GPIO.LOW)
            GPIO.output(6, GPIO.HIGH)
            GPIO.output(13, GPIO.HIGH)
            GPIO.output(19, GPIO.HIGH)
            GPIO.output(26, GPIO.HIGH)
        elif intCount == 29:
            GPIO.output(5, GPIO.HIGH)
            GPIO.output(6, GPIO.LOW)
            GPIO.output(13, GPIO.HIGH)
            GPIO.output(19, GPIO.HIGH)
            GPIO.output(26, GPIO.HIGH)
        elif intCount == 28:
            GPIO.output(5, GPIO.LOW)
            GPIO.output(6, GPIO.LOW)
            GPIO.output(13, GPIO.HIGH)
            GPIO.output(19, GPIO.HIGH)
            GPIO.output(26, GPIO.HIGH)
        elif intCount == 27:
            GPIO.output(5, GPIO.HIGH)
            GPIO.output(6, GPIO.HIGH)
            GPIO.output(13, GPIO.LOW)
            GPIO.output(19, GPIO.HIGH)
            GPIO.output(26, GPIO.HIGH)
        elif intCount == 26:
            GPIO.output(5, GPIO.LOW)
            GPIO.output(6, GPIO.HIGH)
            GPIO.output(13, GPIO.LOW)
            GPIO.output(19, GPIO.HIGH)
            GPIO.output(26, GPIO.HIGH)
        elif intCount == 25:
            GPIO.output(5, GPIO.HIGH)
            GPIO.output(6, GPIO.LOW)
            GPIO.output(13, GPIO.LOW)
            GPIO.output(19, GPIO.HIGH)
            GPIO.output(26, GPIO.HIGH)
        elif intCount == 24:
            GPIO.output(5, GPIO.LOW)
            GPIO.output(6, GPIO.LOW)
            GPIO.output(13, GPIO.LOW)
            GPIO.output(19, GPIO.HIGH)
            GPIO.output(26, GPIO.HIGH)
        elif intCount == 23:
            GPIO.output(5, GPIO.HIGH)
            GPIO.output(6, GPIO.HIGH)
            GPIO.output(13, GPIO.HIGH)
            GPIO.output(19, GPIO.LOW)
            GPIO.output(26, GPIO.HIGH)
        elif intCount == 22:
            GPIO.output(5, GPIO.LOW)
            GPIO.output(6, GPIO.HIGH)
            GPIO.output(13, GPIO.HIGH)
            GPIO.output(19, GPIO.LOW)
            GPIO.output(26, GPIO.HIGH)
        elif intCount == 21:
            GPIO.output(5, GPIO.HIGH)
            GPIO.output(6, GPIO.LOW)
            GPIO.output(13, GPIO.HIGH)
            GPIO.output(19, GPIO.LOW)
            GPIO.output(26, GPIO.HIGH)
        elif intCount == 20:
            GPIO.output(5, GPIO.LOW)
            GPIO.output(6, GPIO.LOW)
            GPIO.output(13, GPIO.HIGH)
            GPIO.output(19, GPIO.LOW)
            GPIO.output(26, GPIO.HIGH)
        elif intCount == 19:
            GPIO.output(5, GPIO.HIGH)
            GPIO.output(6, GPIO.HIGH)
            GPIO.output(13, GPIO.LOW)
            GPIO.output(19, GPIO.LOW)
            GPIO.output(26, GPIO.HIGH)
        elif intCount == 18:
            GPIO.output(5, GPIO.LOW)
            GPIO.output(6, GPIO.HIGH)
            GPIO.output(13, GPIO.LOW)
            GPIO.output(19, GPIO.LOW)
            GPIO.output(26, GPIO.HIGH)
        elif intCount == 17:
            GPIO.output(5, GPIO.HIGH)
            GPIO.output(6, GPIO.LOW)
            GPIO.output(13, GPIO.LOW)
            GPIO.output(19, GPIO.LOW)
            GPIO.output(26, GPIO.HIGH)
        elif intCount == 16:
            GPIO.output(5, GPIO.LOW)
            GPIO.output(6, GPIO.LOW)
            GPIO.output(13, GPIO.LOW)
            GPIO.output(19, GPIO.LOW)
            GPIO.output(26, GPIO.HIGH)
        elif intCount == 15:
            GPIO.output(5, GPIO.HIGH)
            GPIO.output(6, GPIO.HIGH)
            GPIO.output(13, GPIO.HIGH)
            GPIO.output(19, GPIO.HIGH)
            GPIO.output(26, GPIO.LOW)
        elif intCount == 14:
            GPIO.output(5, GPIO.LOW)
            GPIO.output(6, GPIO.HIGH)
            GPIO.output(13, GPIO.HIGH)
            GPIO.output(19, GPIO.HIGH)
            GPIO.output(26, GPIO.LOW)
        elif intCount == 13:
            GPIO.output(5, GPIO.HIGH)
            GPIO.output(6, GPIO.LOW)
            GPIO.output(13, GPIO.HIGH)
            GPIO.output(19, GPIO.HIGH)
            GPIO.output(26, GPIO.LOW)
        elif intCount == 12:
            GPIO.output(5, GPIO.LOW)
            GPIO.output(6, GPIO.LOW)
            GPIO.output(13, GPIO.HIGH)
            GPIO.output(19, GPIO.HIGH)
            GPIO.output(26, GPIO.LOW)
        elif intCount == 11:
            GPIO.output(5, GPIO.HIGH)
            GPIO.output(6, GPIO.HIGH)
            GPIO.output(13, GPIO.LOW)
            GPIO.output(19, GPIO.HIGH)
            GPIO.output(26, GPIO.LOW)
        elif intCount == 10:
            GPIO.output(5, GPIO.LOW)
            GPIO.output(6, GPIO.HIGH)
            GPIO.output(13, GPIO.LOW)
            GPIO.output(19, GPIO.HIGH)
            GPIO.output(26, GPIO.LOW)
        elif intCount == 9:
            GPIO.output(5, GPIO.HIGH)
            GPIO.output(6, GPIO.LOW)
            GPIO.output(13, GPIO.LOW)
            GPIO.output(19, GPIO.HIGH)
            GPIO.output(26, GPIO.LOW)
        elif intCount == 8:
            GPIO.output(5, GPIO.LOW)
            GPIO.output(6, GPIO.LOW)
            GPIO.output(13, GPIO.LOW)
            GPIO.output(19, GPIO.HIGH)
            GPIO.output(26, GPIO.LOW)
        elif intCount == 7:
            GPIO.output(5, GPIO.HIGH)
            GPIO.output(6, GPIO.HIGH)
            GPIO.output(13, GPIO.HIGH)
            GPIO.output(19, GPIO.LOW)
            GPIO.output(26, GPIO.LOW)
        elif intCount == 6:
            GPIO.output(5, GPIO.LOW)
            GPIO.output(6, GPIO.HIGH)
            GPIO.output(13, GPIO.HIGH)
            GPIO.output(19, GPIO.LOW)
            GPIO.output(26, GPIO.LOW)
        elif intCount == 5:
            GPIO.output(5, GPIO.HIGH)
            GPIO.output(6, GPIO.LOW)
            GPIO.output(13, GPIO.HIGH)
            GPIO.output(19, GPIO.LOW)
            GPIO.output(26, GPIO.LOW)
        elif intCount == 4:
            GPIO.output(5, GPIO.LOW)
            GPIO.output(6, GPIO.LOW)
            GPIO.output(13, GPIO.HIGH)
            GPIO.output(19, GPIO.LOW)
            GPIO.output(26, GPIO.LOW)
        elif intCount == 3:
            GPIO.output(5, GPIO.HIGH)
            GPIO.output(6, GPIO.HIGH)
            GPIO.output(13, GPIO.LOW)
            GPIO.output(19, GPIO.LOW)
            GPIO.output(26, GPIO.LOW)
        elif intCount == 2:
            GPIO.output(5, GPIO.LOW)
            GPIO.output(6, GPIO.HIGH)
            GPIO.output(13, GPIO.LOW)
            GPIO.output(19, GPIO.LOW)
            GPIO.output(26, GPIO.LOW)
        elif intCount == 1:
            GPIO.output(5, GPIO.HIGH)
            GPIO.output(6, GPIO.LOW)
            GPIO.output(13, GPIO.LOW)
            GPIO.output(19, GPIO.LOW)
            GPIO.output(26, GPIO.LOW)
        elif intCount == 0:
            GPIO.output(5, GPIO.LOW)
            GPIO.output(6, GPIO.LOW)
            GPIO.output(13, GPIO.LOW)
            GPIO.output(19, GPIO.LOW)
            GPIO.output(26, GPIO.LOW)
    #loop for repeated flashing
    global intRepeat
    while(intRepeat <= 5) and (intCount == 0):
        intRepeat = intRepeat + 1
        time.sleep(0.4)
        GPIO.output(5, GPIO.HIGH)
        GPIO.output(6, GPIO.LOW)
        GPIO.output(13, GPIO.HIGH)
        GPIO.output(19, GPIO.LOW)
        GPIO.output(26, GPIO.HIGH)
        time.sleep(0.4)
        GPIO.output(5, GPIO.LOW)
        GPIO.output(6, GPIO.HIGH)
        GPIO.output(13, GPIO.LOW)
        GPIO.output(19, GPIO.HIGH)
        GPIO.output(26, GPIO.LOW)
    GPIO.output(5, GPIO.LOW)
    GPIO.output(6, GPIO.LOW)
    GPIO.output(13, GPIO.LOW)
    GPIO.output(19, GPIO.LOW)
    GPIO.output(26, GPIO.LOW)
    intRepeat = 0
    templateData = {
    'intCount' : intCount
    }
    return render_template('index3.html', **templateData)


@app.route('/reset/')
def reset():
    global intCount
    intCount = 0
    GPIO.output(5, GPIO.LOW)
    GPIO.output(6, GPIO.LOW)
    GPIO.output(13, GPIO.LOW)
    GPIO.output(19, GPIO.LOW)
    GPIO.output(26, GPIO.LOW)
    templateData = {
    'intCount' : intCount
    }
    return render_template('index3.html', **templateData)


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

This is my HTML index template

<!DOCTYPE html>
    <body>

        <h1>CountDown Timer 1.0<h1>
        <p>Current time: {{ intCount }}</p>
        <p>
        <form action="/up/">
            <input type="submit" style="height:200px;width:200px" value="Count Up" />
        </form>
        </p>
        <p>
        <form action="/down/">
            <input type="submit" style="height:200px;width:200px" value="Start!" />
        </form>
        </p>
        <p>
        <form action="/reset/">
            <input type="submit" style="height:200px;width:200px" value="Reset/Stop" />
        </form>
        </p>
    </body>
</html>

I have seem other posts of using AJAX but i got no idea how to do that

PS I know the binary LED countdown is inefficient but this will do...



Solution 1:[1]

Ok, first of all, welcome to the programming world!

The solution to that problem is not hard, the another posts that say to use AJAX is 100% correctly, so i made some implementation that can help you.

index3.html file:

<!DOCTYPE html>
<body>

    <h1>CountDown Timer 1.0<h1>
    <p id="count">Current time: {{ intCount }}</p>
    <p>
    <!--onclick is a event that execute some function segment on some click in the element-->
        <button onclick="sendAddComand()" style="height:200px;width:200px"">Count Up</button>
    </p>
    <p>
        <button style="height:200px;width:200px"">Start!</button>
    </p>
    <p>
        <button style="height:200px;width:200px"">Reset/Stop</button>
    </p>
    <p>
    <!--onclick is a event that execute some function segment on some click in the element-->
        <button onclick="getStatus()" style="height:200px;width:200px">Refresh</button>
    </p>
    <script>
        function getStatus(){
            //Fetch is a command to make a HTTP request
            fetch("/getCountStatus",{
                //Set the request method to GET
                method:"GET"
                /*The response is a promise, if you dk what's that, is basically
                a thing that have probability of fail (in this context)
                "then()" if is evething ok, "catch()" if something bad happened
                */
            }).then((Response) => {
                //The response text is a promise too, we need do the same process
                Response.text().then((value) => {
                    //If we got the value, put it in the count
                    /* If you dk what's is that: this is a DOM interaction,
                    i just take the element with "count" id and put the modified text inside it */
                    document.getElementById("count").innerText = "Current time: " + value;
                }).catch(() => {
                    window.alert("fail on get status");
                })
            })
        }
        //Everything here is a basically copy of the code up here
        function sendAddComand(){
            fetch("/up/",{
                method : "GET"
            }).then((Response) => {
                    Response.text().then((text) => {
                        document.getElementById("count").innerText =     
"Current time: " + text;
                })
            })
        }
    </script>
</body>

In the code up here you can see that for each "onclick" event that the button do an function segment is activied, each function segment do a request for a url to the server, that execute some code and return a number to put in the web site's count, look the next code

server.py file:

from distutils.log import debug
from flask import Flask, render_template

app = Flask(__name__)
app.debug = True;


intCount = 0

@app.get("/")
def index():
    return render_template("index3.html")

@app.get("/down/")
def downIt():
    global intCount
    intCount -= 1

    #Do anything here...

    #Here i'm returning the current value of count, so you can get
    #It in you web site
    return str(intCount)

@app.get("/up/")
def upIt():
    global intCount
    intCount += 1

    #Do anything here...


    #Here i'm returning the current value of count, so you can get
    #It in you web site
    return str(intCount)

@app.get("/getCountStatus")
def status():
    global intCount
    return str(intCount)


@app.get("/reset/")
def resetIt():
    global intCount
    intCount = 0;

    # Do anything here...

    return str(intCount) #Again i'm returning the value, to the web site change in the count

Well, i hope that you understood how to make a communication between client and server and send data through it.

Let me know if you can understand it.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 RĂ´mulo peres de moraes