Running python script from html from nodejs - python

Bare with me, i have a pretty complex setting here (i'd be happy to get it simpler)
I have a nodejs server running (for localhost access) the nodejs is reading a file and output in browser
This gives me the possibility to have my own server for testing multiple things so i can access localhost/test.html or localhost/web.php for example. and it works fine.
Now i want to control lights. i have a python script that can do that (and it works very well in terminal)
Now i want to be able to run the script using a simple button on the html page ran by nodejs.
I've tried multiple things, including pythonshell, php, but can't find the working one..
So I can i run a python script from my page outputed in browser by nodejs ?
EDIT :
here is in more detail how evreything is running :
I node a app.js running a simple read file and get url
app.js
http = require("http"),
path = require("path"),
url = require("url"),
fs = require("fs");
function sendError(errCode, errString, response)
{
response.writeHead(errCode, {"Content-Type": "text/plain"});
response.write(errString + "\n");
response.end();
return;
}
function sendFile(err, file, response)
{
if(err) return sendError(500, err, response);
response.writeHead(200);
response.write(file, "binary");
response.end();
}
function getFile(exists, response, localpath)
{
if(!exists) return sendError(404, '404 Not Found', response);
fs.readFile(localpath, "binary",
function(err, file){ sendFile(err, file, response);});
}
function getFilename(request, response)
{
var urlpath = url.parse(request.url).pathname; // following domain or IP and port
var localpath = path.join(process.cwd(), urlpath); // if we are at root
fs.exists(localpath, function(result) { getFile(result, response, localpath)});
}
var server = http.createServer(getFilename);
server.listen(1000);
console.log("Server available...");
from there i can call any files in the same dir, i therefore call a index.html
index.html
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Index</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
</head>
<body class="text-white bg-dark">
<center>
<form method="post">
<input type="submit" value="OFF" name="OFF" onclick="turnOff()">
<input type="submit" value="ON" name="ON" onclick="turnOn()">
</form>
</center>
<script>
function turnOff(){
//something i need to call shell command python3 turnOff.py
}
function turnOn(){
//something i need to call shell command python3 turnOn.py
}
</script>
</body>
</html>
And i have two files turnOn.py and turnOff.py
Thanks

If it is the same server, you can run code in the following way
exec('python code.py');
see: https://medium.com/stackfame/how-to-run-shell-script-file-or-command-using-nodejs-b9f2455cb6b7

Related

Flask Get Request for JSON

I am trying to make an Intranet of Things (IoT) page. I am using Flask for the python backend. I am trying to update the state of my light in real time. I believe the route to go is the AJAX/XMLHttpRequest on the front end. I am struggling to figure out how to send the JSON to the front end from the back end. Every example online seems to be a POST request instead of Get.
I believe I have the object created correctly as well as open and sending it correctly. I think my error is on the python side and not doing request right. I tried copying this example https://gist.github.com/KentaYamada/2eed4af1f6b2adac5cc7c9063acf8720. All the other stack overflow examples seem to do different methods like return or add an if statement for the return. I am not sure example how to setup to return the 'get' argument in request.args.get[]. The suggested potential duplicates only show one end, are in express js with the $ syntax which I'm not familiar with, or something similar
I am currently getting 500 errors. Below is my code.
HTML:
<html> <head>
<meta name = "Viewport" context = "width=device-width. initial-scale=1.0">
<title>Chang's IoT Controls</title>
<link href="{{url_for('static',filename='Styles/Controls.css')}}" rel="stylesheet" type="text/css"/>
</head>
<body>
<h1>Controls</h1>
<p> Controls to control Chang's IoT Hub</p>
<figure class="item">
<img src="{{light}}" id="light" onclick="Power(this)" />
<figcaption id = light1 class="caption">Light</figcaption>
</figure>
<figure class="item">
<img src="{{url_for('static',filename='Images/OffLight.jpg')}}" id="temp" onclick="Power(this)" />
<figcaption class="Temperature" id="state" <span style="border:2px solid black">Here</span></figcaption>
<button type = "button" id="toggle" onclick ="Power(this)" > Change Lights </button>
</figure>
<figure class="item">
<img src="{{temp}}" id="temp" onclick="Power(this)" />
<figcaption id = temperature class="caption">{{degree}}</figcaption>
</figure>
<script>
document.getElementById("state").innerHTML = "reached";
const xhttp = new XMLHttpRequest();
xhttp.onload = function () {
const xmlDoc = JSON.parse(this.responseText);
const status = xmlDoc.Status;
document.getElementById("state").innerHTML = status;
if(status == "On")
{
document.getElementById("temp").src = "{{url_for('static',filename='Images/OnLight.jpg')}}";
}
if(status == "Off")
{
document.getElementById("temp").src = "{{url_for('static',filename='Images/OffLight.jpg')}}";
}
}
xhttp.open("GET",'/get_json');
xhttp.send();
console.log(xhttp.response);
</script>
<p>
Homepage
</p>
</body>
</html>
Python:
from flask import Flask, redirect, url_for, render_template, request
app = Flask(__name__)
#app.route("/", methods=["POST", "GET"])
def home():
imgname = url_for('static', filename='Images/OnLight.jpg')
thermo = url_for('static', filename='Images/Thermometer.png')
heat = 50
# if request.method == "GET":
# file = request.form(url_for('static',filename='test.json'))
# return file
return render_template("Controls.html", light=imgname, temp=thermo, degree=heat)
#app.route('/get_json')
def get_json():
return jsonify(Status= "On")
if __name__=="__main__":
app.run(host="0.0.0.0", port=80)
JSON:
{
"Light":
[{"Status": "On"}]
}
I tried looking at examples including git repos like https://gist.github.com/KentaYamada/2eed4af1f6b2adac5cc7c9063acf8720 as well as stack overflow pages like Getting data from xhr request using python and how to properly get data from javascript to my python flask backend using XMLHttpRequest? as well as looked at the APIs
You can create different routes for html and for json.
For your Json try something like below
#app.route(“/get_json“, methods = [“GET”])
def get_json_to_frontend():
// logic
return jsonify( your response)
for html you can use your home() function that you’ve already created
Assume your response is :
{ "state" : "Ok" }
This is what you're Javascript should look like:
let xhttp = new XMLHttpRequest();
xhttp.onload = () => {
let t = JSON.parse(xhttp.response);
console.log(t.state);
}
xhttp.open("GET", URL);
xhttp.send();
This should work. It's pretty straight forward.

Flask server redirects all connected clients to a page when some event occurs

I'm very new of Flask, JavaScript, HTML, etc. So, probably, this is a silly question.
I have a Flask server with one client connected. When this client pushes a button, the server sends a new page to it.
It's easy and I know how to do it.
Now, suppose there are more than one client connected to the server. Is it possible, and how, to send the new page to all the clients when one of them pushes that button?
I've tried with socketIO, I'm able to make the server traps the button click, and send a text message back to all the clients, but this terminates my successes. I'm not able to make the page change on all the clients side.
When a client connects to 127.0.0.1:5000, the server renders index.html
#app.route('/')
def index():
return render_template('index.html')
this is the index.html
<body>
<input type="text" id="message">
<button id="send">Send</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.1.3/socket.io.min.js"></script>
<script
src="https://code.jquery.com/jquery-3.6.0.js"
integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk="
crossorigin="anonymous"></script>
<script src="{{ url_for('static', filename='script.js')}}"></script>
</body>
and this is the js file
$(document).ready(function() {
var socket = io.connect('http://127.0.0.1:5000');
$('#send').on('click', function() {
var message = $('#message').val();
socket.emit('message from user', message);
});
socket.on('from Flask', function(msg) {
alert(msg);
});
...
When the user clicks on the button, the server uppers the message sent by the client and broadcasts it to all the clients that are connected. Each client then shows it in a popup.
#socketio.on('message from user')
def receive_message_from_user(message):
print ('USER MESSAGE {}'.format(message))
emit ('from Flask', message.upper(), broadcast=True)
My intention is that, each client, instead of receiving this message from the server, goes to the a different page.
I have reviewed the code. The 'from Flask' broadcast does work.
#socketio.on('message from user')
def receive_message_from_user(message):
print ('USER MESSAGE {}'.format(message))
emit('from Flask', message.upper(), broadcast=True)
emit('redirect', {'url': url_for('home')}, broadcast=True)
(js)
socket.on('from Flask', function(msg) {
alert("from flask: " + msg);
});
The think that might have confused you is that it only works if you are not in the index page, this is because home is not importing the script.js. This will make the message appear (although you might want to have two different scripts, otherwise the redirect will also be activated when on the home page).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Home</title>
</head>
<body>
<h1>Home!!</h1>
<script src="{{ url_for('static', filename='script.js')}}"></script>
</body>
</html>

Take out JSON elements out of Socket MQTT in Flask

I'm currently using MQTT-Flask to accomplish sending a payload over MQTT and sockets to my Flask webserver. So far it works well, and I've been attempting to build on what I have and transition the payload into JSON to pack more data into it, so that I can use the variables on different parts of the site.
That said, I'm not able to save have it been recognized as JSON so that I can save the variables from it, and I was hoping someone could point me in the right direction.
So the snippet of data I use in Flask looks as follows:
#mqtt.on_message()
def handle_mqtt_message(client, userdata, message):
data = dict(
topic=message.topic,
payload=message.payload.decode(),
)
socketio.emit('mqtt_message', data=data)
as came standard with the github, and I saw no fault with this, so I kept it.
On the template/index.html it looks as follows:
<script type="text/javascript" src="{{ url_for('static', filename='jquery-3.3.1.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='socket.io.min.js') }}"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
var socket = io.connect('http://' + document.domain + ':' + location.port);
socket.on('mqtt_message', function(data) {
console.log(data);
$('#mqtt_msg').text(data.payload);
})
});
</script>
<div id="mqtt_msg"></div>
I've tried parsing it into JSON.stringify and just trying to take it out as data.timestamp but all of that doesn't seem to work. It feels like it is very straightforward.
The payload I'm pushing looks as follows:
{
"timestamp": 1614708210,
"payload": "432",
"agent": "web_admin"
}
Any help or input would be greatly appreciated.
Create JSON string while sending data
socketio.emit('mqtt_message', data=json.dumps(data))
parse the JSON string on the client-side
socket.on('mqtt_message', (data) => {
console.log(JSON.parse(data));
});
Don't forget to import json package in python
import json

tornado can't load jquery.js?

here is my simple html, when I open the file directly, there is no issue
<html>
<head>
<meta charset="utf-8">a
<title>Demo</title>
</head>
<body>
jQuery
<script src="jquery.js"></script>
<script>
$( document ).ready(function() {
$( "a" ).click(function( event ) {
alert( "The link will no longer take you to jquery.com" );
event.preventDefault();
});
});
</script>
</body>
</html>
However, if i input the http://localhost:8000/ tornaod gives me the error that WARNING:tornado.access:404 GET /jquery.js (::1) 3.00ms
following is my simple tornado code...I am not sure what wrong with my code...
class IndexHandler(tornado.web.RequestHandler):
def get(self):
self.render("./pages/index.html")
app = tornado.web.Application([(r'/test1', Test1Handler),
(r'/test2', Test2Handler),
(r'/test3', Test3Handler),
(r'/', IndexHandler)],
debug=True)
app.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
From what I see, you have only 4 paths specified to be accessible via Tornado: /test1, /test2, test3 and /. There is no path specified to access /jquery.js.
Theck this question to see how to serve static files:
Using Tornado, how do I serve static files and serve a favicon.ico from a different directory than the static path?

How to call a python script with ajax in cherrypy app

I am trying to get the output from a python script and put it into a table in the html of my cherrypy app.
Example app:
import string, os
import cherrypy
file_path = os.getcwd()
html = """<head>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="content-type">
<title>CCMF</title>
<link rel='shortcut icon' type='image/x-icon' href='img/favicon.ico' />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
function b1() {
var request = $.ajax({
url: "b1.py",
type: "POST",
dataType: "text"
});
request.done(function(msg) {
$("#output").html(msg);
});
request.fail(function(jqXHR, textStatus) {
alert( "Request failed: " + textStatus );
});
}
</script>
</head>
<button onclick="b1()">call b1.py</button>
...
<td id = "output"; style="vertical-align: top; height: 90%; width: 100%;">
<--output goes here -->
</td>
...
</html>
"""
class ccmf(object):
#cherrypy.expose
def index(self):
return html
if __name__ == '__main__':
cherrypy.server.socket_host = "127.0.0.1"
cherrypy.server.socket_port = 8084
config = {
"/img": {
"tools.staticdir.on": True,
"tools.staticdir.dir": os.path.join(file_path, "img"),
}
}
cherrypy.tree.mount(ccmf(), "/", config=config)
cherrypy.engine.start()
cherrypy.engine.block()
and here's the example python script b1.py:
def b1():
op = "ajax b1 pushed"
print op
return op
b1()
The ajax get's called but returns the failure alert. I have tried GET, POST, "text", "html", b1.py is in the same directory, no joy. All currently running on my local box.
Any hints greatly appreciated!
You are completely misunderstanding how modern, CherryPy's for instance, routing works. Unlike outdated approaches that were commonly employed with CGI and Apache's mod_* (mod_php, mod_python, etc.), where you directly point to the file containing the script with URL, modern routing is an application level activity.
Your application receives all requests and dispatches them according to the established method. CherryPy in that sense has two major approaches: built-in object tree dispatcher and Routes adapter. For most simple and mid-level cases built-in dispatcher is fair enough.
Basically it can look like this.
app.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import cherrypy
from cherrypy.lib.static import serve_file
path = os.path.abspath(os.path.dirname(__file__))
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8
}
}
class App:
#cherrypy.expose
def index(self):
return serve_file(os.path.join(path, 'index.html'))
#cherrypy.expose
#cherrypy.tools.json_out()
def getData(self):
return {
'foo' : 'bar',
'baz' : 'another one'
}
if __name__ == '__main__':
cherrypy.quickstart(App(), '/', config)
index.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv='content-type' content='text/html; charset=utf-8'>
<title>CCMF</title>
<script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'></script>
<script type='text/javascript'>
$(document).ready(function()
{
$('button').on('click', function()
{
var request = $.ajax({'url': '/getData'});
request.done(function(response)
{
$('#foo').text(response.foo);
$('#baz').text(response.baz);
});
request.fail(function(jqXHR, textStatus)
{
alert('Request failed: ' + textStatus);
});
})
});
</script>
</head>
<body>
<button>make ajax call</button>
<h1>Foo</h1>
<div id='foo'></div>
<h1>Baz</h1>
<div id='baz'></div>
</body>
</html>

Categories