0

I have a small web app for which the back-end is a Flask+SocketIO server. I would like to get some data from an ESP8266 into my app. The most simple way to achieve this I could think of was to have the micro controller connected directly to the back-end.

I am using the timum-viw library with this example code to implement the client on the micro controller.

The problem is that on trying to run the example I get

(12765) accepted ('192.168.0.11', 59848)
192.168.0.11 - - [06/Jul/2020 18:15:25] "GET /socket.io/?transport=websocket HTTP/1.1" 400 122 0.000265
192.168.0.11 - - [06/Jul/2020 18:15:31] code 400, message Bad request syntax ('This is a webSocket client!')
192.168.0.11 - - [06/Jul/2020 18:15:31] "This is a webSocket client!" 400 -

in the terminal window of the dev server. (The IP belongs to the ESP8266.)

I have the same experience with the arduinoWebSockets library and the WebSocketClientSocketIO example.

Can you help me figure out what the problem is?

Update

Everything is hosted locally at this point. I am running the flask dev server with python3 flask_main.py, eventlet is installed.

The minimal code that manifests the problem:

Arduino:

#include <SocketIoClient.h>
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <Hash.h>

#define USE_SERIAL  Serial
#define SSID_primary        "**********"
#define WIFI_PWD_primary    "**********"
#define SERVER_IP "192.168.0.7"
#define SERVER_PORT 5005

ESP8266WiFiMulti wifiMulti;
SocketIoClient socketIOClient;

void setup() {

//// set up serial communication
    USE_SERIAL.begin(115200);
    USE_SERIAL.setDebugOutput(true);

    for(uint8_t t = 4; t > 0; t--) {
        USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
        USE_SERIAL.flush();
        delay(1000);
    }

//// connect to some access point
    wifiMulti.addAP(SSID_primary, WIFI_PWD_primary);

    while(wifiMulti.run() != WL_CONNECTED) {
        delay(500);
        USE_SERIAL.print("Looking for WiFi ");
    }

    USE_SERIAL.printf("Connected to %s\n", WiFi.SSID().c_str());
    USE_SERIAL.printf("My local IP address is %s\n", WiFi.localIP().toString().c_str());

//// set up socket communication
    socketIOClient.begin(SERVER_IP, SERVER_PORT);
}

void loop() {
    socketIOClient.emit("message", "\"hi there :)\"");
    socketIOClient.loop();
    delay(1000);
}

Flask minimal code:

from flask import Flask, render_template, request
from flask_socketio import SocketIO

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)

@socketio.on('message')
def handle_message_event(msg):
    print('received msg from {} : {}'.format(request.remote_addr, str(msg)))

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

The code below is for debugging only. I do not wish to use them in any form later.

Weirdly enough the Arduino code works fine with a node.js server:

var app = require('express')();
var http = require('http').createServer(app);
var io = require('socket.io')(5005);

io.attach(http, {
    pingInterval: 10000,
    pingTimeout: 5000,
    cookie: false
});

io.on('connection', function (socket) {

    console.log('user connected');

    socket.on('disconnect', function () {
        console.log('user disconnected');
    });
    socket.on('message', function (msg) {
        console.log("message: "+msg);
    });
    timeout();
});

http.listen();

Could there be something wrong with my Flask? It responds to connections from this:

from socketIO_client import SocketIO, LoggingNamespace

socketIO = SocketIO('localhost', 5005, LoggingNamespace)

while True:
    _ = raw_input("> ")
    socketIO.emit('message', "hello 2")

But the node server does not!

Update 2

So I went ahead and looked at the communication with wire shark: Python client & Flask server (works) enter image description here

The payload of frame 27:

Hypertext Transfer Protocol
    GET /socket.io/?EIO=3&transport=websocket&sid=8f47e9a521404b66b23cd985cdee049d HTTP/1.1\r\n
    Upgrade: websocket\r\n
    Host: localhost:5005\r\n
    Origin: http://localhost:5005\r\n
    Sec-WebSocket-Key: TQ589ew7EgwDILWb50Eu9Q==\r\n
    Sec-WebSocket-Version: 13\r\n
    Connection: upgrade\r\n
    Connection: keep-alive\r\n
    Accept-Encoding: gzip, deflate\r\n
    Accept: */*\r\n
    User-Agent: python-requests/2.18.4\r\n
    \r\n
    [Full request URI: http://localhost:5005/socket.io/?EIO=3&transport=websocket&sid=8f47e9a521404b66b23cd985cdee049d]
    [HTTP request 1/1]
    [Response in frame: 29]

Doing the same with the arduino & flask (does not work) enter image description here

The payload of frame 34:

Hypertext Transfer Protocol
    GET /socket.io/?transport=websocket HTTP/1.1\r\n
    Host: 192.168.0.7:5005\r\n
    Connection: Upgrade\r\n
    Upgrade: websocket\r\n
    Sec-WebSocket-Version: 13\r\n
    Sec-WebSocket-Key: D9+/7YOHoA8lW7a/0V8vsA==\r\n
    Sec-WebSocket-Protocol: arduino\r\n
    Origin: file://\r\n
    User-Agent: arduino-WebSocket-Client\r\n
    \r\n
    [Full request URI: http://192.168.0.7:5005/socket.io/?transport=websocket]
    [HTTP request 1/1]
    [Response in frame: 36]
mr_tuna
  • 185
  • 1
  • 7
  • Please also post your current relevant code on here, and explain what you are trying to do with it. Also where/how are you hosting the flask app? Is it local, is it on a cloud? – Akib Rhast Jul 06 '20 at 19:25
  • Why do you need Flask to begin with if you are using socket for establishing connection and sending msg? – hcheung Jul 07 '20 at 01:04
  • I do have Web App in which I am trying to graph temperature that is coming from the micro controller. Flask would receive the data from the micro controller and send it to the browser. Here the Flask example is minimal but for my app it is around 200 lines. – mr_tuna Jul 07 '20 at 01:10

1 Answers1

0

So it turns out that Flask freaks out about the

Origin: file://\r\n 

part because it thinks it is CORS. This is why this answer actually works, however I think it is the wrong fix. Removing this extra header entry is the right way to go about this. This is most simply done by editing this line to match this:

    _client.extraHeaders = WEBSOCKETS_STRING("");

in your local library.

There goes hours of research :D

mr_tuna
  • 185
  • 1
  • 7