I'm trying to make a simple web interface for my arduino using a raspberry pi. I want to click a link that i create in html and send the string "on" to the python program so it can tell the arduino to turn on.
Here's my python code
import serial
from flask import Flask, render_template, request
import datetime
app = Flask(__name__)
ser = serial.Serial('/dev/ttyACM0', 9600)
#app.route("/<action>")
def action(action):
print action
#command = ""
#while command != "done":
# command = raw_input("what do you want? ")
if action == "on":
ser.write('1')
elif action == "off":
ser.write('0')
return render_template('index.html', **templateData)
#app.route("/")
def display():
now = datetime.datetime.now()
timeString = now.strftime("%Y-%m-%d %H:%M")
templateData = {
'title' : 'arduino',
'time' : timeString
}
return render_template('index.html', **templateData)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8080, debug=True)
and here's my html code
<!DOCTYPE html>
<head>
<title>{{title}}</title>
</head>
<body>
<p>The time at server is {{time}}</p>
<p>
The LED is currently off (turn on)
</p>
<body>
</html>
When someone clicks the link turn on I want the string on to be sent to the action method so that it can take it from there. Instead what it does is go to the /on directory which is not surprising. I've looked everywhere and can't find how to do this. This is my first time ever using Flask and I'm fairly new to python so please don't be too harsh if I'm completely off.
You could just redirect after you take the action
from flask import Flask, render_template, request, redirect
#app.route("/<action>")
def action(action):
...
return redirect(url_for('display'))
Related
This question already has answers here:
Are global variables thread-safe in Flask? How do I share data between requests?
(4 answers)
Closed 11 months ago.
I run thin code.
And I want that after 20 seconds that the variable msg will get the value "hello msg2".
And if I refresh the page I see there "hello msg2" instead of "msg1".
from flask import Flask, render_template
import time
mag = "msg1"
app = Flask(__name__)
#app.route("/")
def home():
return render_template("home.html")
#app.route("/index.html")
def user():
return render_template("index.html", msg=msg)
if __name__ == "__main__":
app.run(port=7654, debug=True)
The index.html
<!doctype html>
<html>
<head>
<title>Home page</title>
</head>
<body>
<h1>Home Page!5 {{ msg }} </h1>
</body>
</html>
It is possible? Because I could not run any more commands in Python while the site was running.
You can use threading to spawn up a background thread to take care of updating value of msg. Use time.sleep() to add a delay to the execution.
from flask import Flask, render_template
import time
import threading
msg = "msg1"
# utility to change msg variable
def change_msg(delay=20):
time.sleep(delay)
global msg
msg = "msg2"
app = Flask(__name__)
#app.route("/")
def home():
return render_template("home.html")
#app.route("/index.html")
def user():
return render_template("index.html", msg=msg)
if __name__ == "__main__":
# spawn a thread that changes value of msg after a delay
t = threading.Thread(target=change_msg)
t.start()
app.run(port=7654, debug=True)
You'll need some Javascript. The process you're looking at is
Load the page which makes a call to your server (python)
Check for the presence of a cookie which tells you the page has been loaded before. If this cookie is not present, you return "msg1" and set a cookie letting you know you've returned "msg1". If the cookie is present, then you return "hello msg2" and you don't have to set the cookie again.
This part is where Javascript comes in - After 20 seconds, make another call to your server. You can do this asynchronously so that your page is not reloaded. The cookie will be sent along and step 2 above comes into play.
The easiest way to do what you asked for is a Timer. In your case the content of some_function() should be in your handler function user().
from threading import Timer
from time import sleep
msg = "msg1"
def setMessage():
global msg
msg = "msg2"
print("Message has changed")
def some_function():
global msg
timer = Timer(1.0, setMessage)
timer.start()
print(msg)
some_function()
sleep(3)
some_function()
Expected output:
msg1
Message has changed
msg2
Message has changed
Note: setMessage() is called twice here, but you could check if the message is already msg2 before starting the timer to prevent this from happening.
If what you actually want is concurrency or parallelism you should have a look at Python Threading or for asynchronous programming at asyncio.
I have a Python code which is using NLTK and Flask for creating a chatbot that works on a local server.
After I run or execute the code, the html page opens on the local server and I give a input, but the input doesn't seem to pass to my python code. A prompt appears on my python console where the chatbot takes the input and runs.
I have tinkered a lot with the code, running different forms of it about 30-40times, debugging it and doing a lot of trial and error.
The below code is the only one that seems to run without any error, but the output displayed by the bot on the Html page is "none".
Any help or advice is appreciated. I'm new to Flask and NLTK. Thank you.
This is my Python code
from nltk.chat.util import Chat, reflections
from flask import Flask, render_template, request
pairs = [
[
r"my name is (.*)",
["Hello %1, How are you today ?", ]
],
[
r"how are you ?",
["I'm doing good\nHow about You ?", ]
],
[
r"sorry (.*)",
["Its alright", "Its OK, never mind", ]
],
[
r"hi|hey|hello",
["Hello", "Hey there", ]
],
]
app = Flask(__name__, template_folder='templates')
#app.route('/', methods=['GET', 'POST'])
def samplefunction():
if request.method == 'GET':
return render_template('new.html')
if request.method == 'POST':
greetIn = request.form['human']
greetOut = c(greetIn)
return render_template('new.html',bot1=greetOut)
def c(x):
chat=Chat(pairs,reflections)
return chat.converse(x)
if __name__ == '__main__':
app. run(host='127.0.4.21', port=5000, debug=True)
The html template used is - new.html, the following :
<html>
<head>
<title>BOT</title>
<script>
var bot = {{ bot }}
</script>
</head>
<body>
<h1>Hello, type something to begin!</h1>
<form method='post'>
Human: <input type='text' name='human'><br>
Bot1: {{bot1}}<br>
<input type="submit" name="action">
</form>
</body>
</html>
I had to change the code in the nltk.chat.util package, and give a return type for the converse() method, it initially only had a print statement and no return.
The original code was
def converse(self, quit="quit"):
user_input = ""
while user_input != quit:
user_input = quit
try:
user_input = input(">")
except EOFError:
print(user_input)
if user_input:
while user_input[-1] in "!.":
user_input = user_input[:-1]
print(self.respond(user_input))
The changed code :
def converse(self, quit="quit"):
user_input = ""
while user_input != quit:
user_input = quit
try:
user_input = input(">")
except EOFError:
print(user_input)
if user_input:
while user_input[-1] in "!.":
user_input = user_input[:-1]
return(self.respond(user_input))
I had to remove the print statement and put a return method.
Try using chat.respond(x) instead of chat.converse.
I've been trying to get this flask server to update itself with data generated from a loop that runs on a a .py script when called for by the user via push button on webpage. I've been looking into recommended solutions and have seen websockets (sockets.io), ajax, nodejs come up. I understand that i need to implement some form of js in my project, and ajax looked to be the most simple (so i thought). I only have about 3 weeks of experience programming in python. Mainly i look for examples close to what i want, and then try to modify it to suit my needs, but haven't found any examples for what i'm looking for. Even then, my general newness to programming means that the more examples i "tack on" the more likely i am to degrade the overall structure of what i've already accomplished.
Goal
The goal is to update a value displayed on the page without a reload but instead have js update the value every second. The value is generated from a x=x+1 counter in my .py file. This will be replaced by sensor inputs gathered from my Rpi later.
Actual results
When i run the current code,
my html elements get double posted so i see what i've put into the index.html file twice although the second button elements don't actually respond to clicking,
I also get an endless stream of Posts in my terminal window.
Clicking on the button elements no longer execute my loop in the .py file and instead displays "Method not allowed"
What i've tried
I've tried to implement setTmeout in my html file as a way to call back to the python app and get an updated value (the x=x+1) every second. I've read posts around using setTimeout as a way to deal with issues using setInterval. Due to the variety of ways i've seen ajax calls employed and learning resources being primarily structured towards forms, databases, and chat apps, most of my searches aren't bringing up anything new for me to learn from that might help. I'm currently doing ajax tutorials hoping to come accross something i can use, any help would be greatly appreciated.
ajaxTest.py My python flask file
import threading
import time
from flask import Flask, render_template, jsonify, request
import RPi.GPIO as GPIO
import datetime
from datetime import datetime
from datetime import timedelta
app = Flask(__name__)
bioR_on = False
ledGrnSts = 0
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
air = 21
light = 20
waste = 16
feed = 12
water = 26
pinList = [21,20,16,12,26]
def pump(pin):
GPIO.output(pin, GPIO.LOW)
print(pin,'on')
time.sleep(1)
GPIO.output(pin, GPIO.HIGH)
print(pin, 'off')
time.sleep(1)
def on(pin):
GPIO.output(pin, GPIO.LOW)
#app.route("/")
def index():
templateData = {
'title' : 'Bioreactor output Status!',
'ledGrn' : ledGrnSts,
}
return render_template('index.html', **templateData)
#app.route('/<deviceName>/<action>', methods = ["POST"])
def start(deviceName, action):
# script for Pi Relays
def run():
if action == "on":
alarm = datetime.now() + timedelta(seconds =10)
global bioR_on
bioR_on = True
while bioR_on:
tday = datetime.now()
time.sleep(1)
#feed(tday, alarm)
x=x+1
return jsonify(x)
GPIO.setmode(GPIO.BCM)
for i in pinList:
GPIO.setup (i, GPIO.OUT)
GPIO.output(i, GPIO.HIGH)
on(air)
on(light)
print(tday)
if tday >= alarm:
print('alarm activated')
# run = False
pump(waste)
print('waste activated')
pump(feed)
print('feed on')
GPIO.cleanup()
alarm = datetime.now() + timedelta(seconds =10)
print('next feeding time ', alarm)
time.sleep(1)
if action == 'off':
bioR_on = False
#return "off"
GPIO.cleanup()
thread = threading.Thread(target=run)
thread.start()
templateData = {
'ledGrn' : ledGrnSts,
}
return render_template('index.html', **templateData)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80, debug=True, threaded=True)
My index.html file
<!DOCTYPE html>
<head>
<title>BioReactor Control</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href='../static/style.css'/>
</head>
<body>
<h1>Actuators</h1>
<h2> Status </h2>
<h3> GRN LED ==> {{ ledGrn }}</h3>
<br>
<h2> Commands </h2>
<h3>
Activate Bioreactor Ctrl ==>
TURN ON
TURN OFF
</h3>
<h3>
Current Count
</h3>
<p id="demo"></p>
<script>
setTimeout($.ajax({
url: '/<deviceName>/<action>',
type: 'POST',
success: function(response) {
console.log(response);
$("#num").html(response);
},
error: function(error) {
console.log(error);
}
}), 1000);
</script>
<h1>Output</h1>
<h1 id="num"></h1>
</body>
</html>
Picture of results
I created minimal code which uses AJAX to get new value every 1 second.
I use setInterval to repeate it every 1 second. I also uses function(){ $.ajax ... } to create function which is not executed at once but setInterval will call it every 1 second. Without function(){...} code $.ajax was executed at start and its result was used as function executed every 1 second - but it returns nothing - so finally it updated value only once (at start) and later setInterval was running nothing.
I added current time to see if it is still running.
buttons run function '/<device>/<action>' which start and stop thread but AJAX uses /update to get current value.
I use render_template_string to have all code in one file - so other people can easily copy and test it.
I reduced HTML to minimal. To make sure I put <h1> before script which needs these tags.
I didn't tested it with global=True which may run it in new threads and it can make problem.
from flask import Flask, request, render_template_string, jsonify
import datetime
import time
import threading
app = Flask(__name__)
running = False # to control loop in thread
value = 0
def rpi_function():
global value
print('start of thread')
while running: # global variable to stop loop
value += 1
time.sleep(1)
print('stop of thread')
#app.route('/')
#app.route('/<device>/<action>')
def index(device=None, action=None):
global running
global value
if device:
if action == 'on':
if not running:
print('start')
running = True
threading.Thread(target=rpi_function).start()
else:
print('already running')
elif action == 'off':
if running:
print('stop')
running = False # it should stop thread
else:
print('not running')
return render_template_string('''<!DOCTYPE html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
TURN ON
TURN OFF
<h1 id="num"></h1>
<h1 id="time"></h1>
<script>
setInterval(function(){$.ajax({
url: '/update',
type: 'POST',
success: function(response) {
console.log(response);
$("#num").html(response["value"]);
$("#time").html(response["time"]);
},
error: function(error) {
console.log(error);
}
})}, 1000);
</script>
</body>
</html>
''')
#app.route('/update', methods=['POST'])
def update():
return jsonify({
'value': value,
'time': datetime.datetime.now().strftime("%H:%M:%S"),
})
app.run() #debug=True
This question already has an answer here:
Flask: A RESTful API and SocketIO Server
(1 answer)
Closed 7 years ago.
This seems like a very simple problem but it's got me confused nonetheless, I have a Flask application that serves up a webpage and communicates with that page via Socket.io. The Flask application looks like this:
app = Flask(__name__)
socketio = SocketIO(app)
#socketio.on_error()
def error_handler(e):
print e
#this fires
#socketio.on("connect")
def connect():
print "connected"
#this does not
#socketio.on('test')
def test_handler(message):
print "TEST WORKS"
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0')
socketio.run(app)
My page itself is very simple:
<!doctype html>
<html>
<head>
<title>Flask Socket.IO test</title>
<style>
body { font: 13px Helvetica, Arial; }
</style>
<script src="socket.io-1.4.3.js"></script>
<script src="jquery-2.2.0.min.js"></script>
<script>
var socket = io("192.168.42.1:5000");
socket.on('connect', function() {
console.log(" connected ");
});
$(document).ready( function() {
$( '.startBtn' ).click(function() {
console.log("ok");
socket.emit('test', {data:"start!"});
});
});
</script>
</head>
<body>
<div class="startBtn">
<h1>START</h1>
</div>
</body>
</html>
I see on both sides that they connect (i.e. the connect event is triggered on both sides) but nothing that I send from the page to the server is received. I'm guessing somehow I have things misconfigured but the connection being established makes me think otherwise.
So the problem seems to be in how I was setting up the Flask application and socketio. Changing it to this:
app = Flask(__name__)
socketio = SocketIO(app, async_mode='eventlet')
#app.route('/')
def index():
return render_template('index.html')
#socketio.on('test')
def josh_test(message):
print "test"
if __name__ == '__main__':
socketio.run(app, debug=True)
it now all works fantastically with no changes to the HTML file. My previous version had:
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0')
socketio.run(app)
and that was what was causing the problems.
My knowledge in web frameworks are pretty bad. I have a build a machine learning model in python and it takes a set of strings as an input and return results. After searching on the web I came across with Flask. But what I don't know is how to actually create a flask app to actually take a string and allow user to submit and pass that string to my machine learning python script and return results. This is all I have so far
import threading
import subprocess
import os
import sys
from flask import Flask
from flask import render_template, abort
app = Flask(__name__)
app.debug = True
def run_script():
theproc = subprocess.Popen([sys.executable, "ML_script.py"])
theproc.communicate()
if __name__ == "__main__":
app.run()
If you can point to an example or provide a solution /skeleton that would be fantastic.
You can use your machine learning functions like any other Python function there is no need for subprocess. Setup your app:
from flask import Flask
from flask import render_template, abort, jsonify, request,redirect, json
from my_app.machine_learning import analyzer
app = Flask(__name__)
app.debug = True
#app.route('/')
def index():
return render_template('index.html')
#app.route('/learning', methods=['POST'])
def learning():
data = json.loads(request.data)
# data == {"userInput": "whatever text you entered"}
response = analyzer(data)
return jsonify(response)
if __name__ == '__main__':
app.run()
I used a stand in name for your machine learning module but analyzer() should be a function in that module that calls all your other functions needed to do your computations and returns a dictionary that has your results in it. So something like this:
def analyzer(data):
vocab = build_vocab(training_data)
cl = train_classifier(vocab, trianing_data)
results = cl.predict(data)
results = format_results_to_dict()
return results
The template is pretty straight forward:
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="../static/script.js"></script>
</script>
</head>
<body>
<h1>Calculation</h1>
<h1>Test Page</h1>
<input id="user-input" placeholder="Text to be analyzed"></input>
<p id="results">Results will go here<p>
<button id="submit">Submit</button>
</body>
</html>
And the JS script to tie it all together:
$(document).ready(function(){
$("#submit").click(function(event){
var uInput = $("#user-input").val();
$.ajax({
type: "POST",
url: '/learning',
data: JSON.stringify({userInput: uInput}),
contentType: 'application/json',
success: function(response){
$("#results").text(response.results);
},
});
});
});