Search code examples
javascriptpythonflaskraspberry-pigpio

I'm trying to find a way of using a GPIO input on the server side to redirect the client side to another web page rpi, RPi.GPIO, python, flask,j s


I'm working on a Escape room project. Effectively, the behavior I'm trying to create is as follows:

Web brower displays part of the web app in the usual way. From this point on, there will be no further inputs from the keyboard/mouse on the client. I've solved for time based changes using JS, so I can load the web app and after a period of time has JS redirects to another app route. Here's where I start struggling as well as the time based redirects I want a GPIO input on the server side to make the browser redirect to another app route.

I'm using threading, so when the app route function runs it starts the thread running on the function that's waiting for the GPIO input. The waitfortrigger function works and runs as it should until I try to return a redirect. At that point I get an unknown context error in the Flask debug log. I can fix the error using app.app_context and app.app_context.push. At that point the waitfortrigger function runs without error but doesn't cause the redirect on the client side. I've also tried using the copy_current_context decorator but don't really understand how to use it and had no success. You might note that I'm using a URL for the redirect rather than the url_for function. Thats because without a client side request url_for can't construct the URL I'm trying to redirect to. Using a full URL really isn't an issue for what I'm trying to do.

I think I'm correct in saying the reason it doesn't work on the client side is because the request doe not come from the client side and is in a different thread from the main app, so that it doesn't understand what to redirect.

Here's a simplified version of the code that im trying:

from flask import Flask, render_template, redirect, url_for, session, logging
import RPi.GPIO as GPIO
import threading

app = Flask(__name__)
input_pin = 18

def gpio_setup():
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(input_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)

def waitfortrigger():
    while GPIO.input(input_pin) == GPIO.HIGH:
        continue
    else:
        con.push()
        return redirect('http://192.168.0.17:5000/page2')

@app.route('/')
def home():
    trig_thread.start()
    global con
    con = app.app_context()
    return render_template('home.html')

@app.route('/page2')
def page2():
    GPIO.cleanup()
    return render_template('page2.html')

if __name__ == '__main__':
    gpio_setup()
    app.secret_key='test'
    trig_thread = threading.Thread(target=waitfortrigger)
    app.run(debug=True, host='0.0.0.0')

What I'm thinking now: maybe there's a way I can use the waitfortrigger function to update something on the server side when it sees the GPIO input and in turn monitor something with JS and then redirect in JS on the client side?

Or maybe using Flask for a web app for this isn't the best solution? I'm learning as I go so would appreciate any suggestion.


Solution

  • In the end I worked out away to do this.... The function that takes the input from the rpi GPIO now creates a file. In my main app I created a new flask route with an if statement. If the file doesn’t exists the function returns a 404. In js on the client side I query the url, if it gets a 200 back which only happens when the file exists it does a redirect.

    Effectively making it possible to make a change server side redirect the client side.

    I changed the input to pwm so and effectively created a safe tumbler lock, which when the code is entered correctly redirects the web app displayed on the screen in the escape room.

    Thanks to the person who took the time to correct my spelling and grammar in my original question.

    Now if I can just work out why my rpi is double executing my code hmmm