0

In a Raspberry Pi I use Flask to serve a web page, which uses JavaScript to post to a Python script.

Folder structure:

/home/pi/Elithion/app.py
/home/pi/Elithion/templates/index.html
/home/pi/Elithion/static/wificonfig.py

app.py (Python code using Flask)

from flask import Flask, render_template, url_for

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def index():
    return render_template('index.html')

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

index.html, JavaScript:

function ReqWifiConfig(selectedWiFiNetwork, wiFiPassword) { // Request setting the WiFi configuration

    // Constants
    var WifiConfigScript = '/static/wificonfig.py';
    var ContentKey = 'Content-type';
    var ContentVal = 'application/x-www-form-urlencoded';

    // Send the wifi login credentials to the Python script using AJAX
    var xmlhttp = new XMLHttpRequest();     
    xmlhttp.onreadystatechange=function() {
        if (xmlhttp.readyState==4 && xmlhttp.status==200){
            ...
        }   
        else if (xmlhttp.readyState==4) {
            alert(xmlhttp.status + xmlhttp.statusText); 
        }
    }
    xmlhttp.open("POST", WifiConfigScript, true);  
    xmlhttp.setRequestHeader(ContentKey, ContentVal);
    var postData = 'nw=' + selectedWiFiNetwork + '&pw=' + wiFiPassword;
    xmlhttp.send(postData);     
}

This results in this alert in browser:

127.0.0.1:5000 says: 405METHOD NOT ALLOWED

and this message in the terminal:

127.0.0.1 - - (date) "POST / static/wificonfig.py HTTP/1.1 405 -

If I change "POST" to "GET", it returns the text in the script, so I know the paths are right.

I checked these StackOverflow answers, and they did not help, because I do have the right path, I am not using a HTML form, and CORS does not apply:

Davide Andrea
  • 1,357
  • 2
  • 15
  • 39
  • 2
    Why are you posting to '/static/wificonfig.py' when your route is just `/`? – Daniel Roseman Sep 22 '17 at 16:04
  • Because that's where the script is, and that's where Flask wants you to place files (images and such). Now, if I should place the script elsewhere, I am eager to learn. Do you think that's my problem? – Davide Andrea Sep 22 '17 at 16:14
  • @Daniel Roseman because if I move the script to the /home/pi/Elithion/, and change the line to var WifiConfigScript = '/wificonfig.py'; I get a 404. I also tried var WifiConfigScript = 'wificonfig.py'; and var WifiConfigScript = 'Elithion/wificonfig.py'; – Davide Andrea Sep 22 '17 at 16:19

2 Answers2

3

You can't post to static files. If you have Python code you want to run, you do that in a Flask view function. Move your script next to your application so it's importable, import it, call it, and return a response.

from flask import request, jsonify
from import wificonfig import do_config

@app.route('/wificonfig', methods=['POST'])
def wificonfig():
    result = do_config(nw=request.form['nw'], pw=request.form['pw'])
    return jsonify(result)

The JavaScript in your template posts to this route, not to wificonfig.py. Generate the URL with url_for and use tojson since you're using the value in JavaScript.

var wifiConfigScript = {{ url_for('wificonfig')|tojson }};
davidism
  • 121,510
  • 29
  • 395
  • 339
1

Solved it, thanks to davidism's clarifications.

Folder structure:

/home/pi/Elithion/app.py
/home/pi/Elithion/templates/index.html
/home/pi/Elithion/wificonfig.py

app.py (Python code using Flask)

from flask import Flask, render_template, request
import wificonfig

app = Flask(__name__)

# Show the HTML page
@app.route('/')
def index():
    return render_template('index.html')

# Service the POST request
@app.route('/postService', methods=['POST'])
def postService():
    wifiStatus = 'fail'
    if request.method == 'POST':
        nw = request.form['nw'] # WiFi network
        pw = request.form['pw'] # WiFi Password
        wifiStatus = wificonfig.configwifi(nw, pw)
    return wifiStatus

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

wificonfig.py script:

def configwifi(nw, np):
    """ Sign onto the WiFi specified network with the given password """
    # ... Code to sign onto the WiFi network
    return 'OK'

index.html, JavaScript:

function ReqWifiConfig(selectedWiFiNetwork, wiFiPassword) { // Request setting the WiFi configuration

    // Constants
    var  WifiConfigScript = '/postService';
    var ContentKey = 'Content-type';
    var ContentVal = 'application/x-www-form-urlencoded';

    // Send the login credentials to the Python script using AJAX
    var xmlhttp = new XMLHttpRequest();     
    xmlhttp.onreadystatechange=function() {
        if (xmlhttp.readyState==4 && xmlhttp.status==200){
            alert(xmlhttp.status + xmlhttp.statusText); // Returns 'OK'
        }
    }
    xmlhttp.open("POST", WifiConfigScript, true);
    xmlhttp.setRequestHeader(ContentKey, ContentVal);
    var postData = 'nw=' + selectedWiFiNetwork + '&pw=' + wiFiPassword;
    xmlhttp.send(postData);     
}
Davide Andrea
  • 1,357
  • 2
  • 15
  • 39