Search code examples
flaskwebsocketserveresp8266

How fix the code 400, message Bad request version ('client!')


I have some code where the arduino Esp8266 is supposed to connect to a flask server hosted on a pi 4 I can get them to connect but I end up getting "192.168.1.20 - - [16/Aug/2023 12:08:59] code 400, message Bad request version ('client!') 192.168.1.20 - - [16/Aug/2023 12:08:59] "This is a webSocket client!" 400 -"

I posted all of the code below exept for the index.html.

any help is greatly appreciated

python

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

app = Flask(__name__)
socketio = SocketIO(app)

# Store a list of discovered Arduino devices
discovered_devices = []

@app.route('/')
def index():
    hostname = 'arduino20'  # Replace with the actual hostname
    return render_template('index.html', discovered_devices=discovered_devices, hostname=hostname)

@app.route('/send_message', methods=['POST'])
def send_message():
    message = request.form['message']
    
    # Send the message to all discovered Arduino devices
    for device in discovered_devices:
        try:
            arduino_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            arduino_socket.connect((device['ip'], device['port']))
            arduino_socket.sendall((message + '\r').encode())  # Add '\r' to the end of the message
            arduino_response = arduino_socket.recv(1024).decode()
            arduino_socket.close()
            
            # Emit the Arduino response through WebSocket
            socketio.emit('arduino_response', {'response': arduino_response})

        except Exception as e:
            print(f"Error sending message to {device['ip']}: {str(e)}")
    
    return "Message sent to all discovered Arduino devices"

@socketio.on('connect')
def handle_connect():
    print('WebSocket client connected')
    # Emit the discovery event to all connected clients
    for device in discovered_devices:
        socketio.emit('discovery', {'hostname': device['hostname'], 'ip': device['ip'], 'port': device['port']})

@socketio.on('discovery')
def handle_discovery(data):
    # Add the discovered device to the list
    discovered_devices.append({'hostname': data['hostname'], 'ip': data['ip'], 'port': data['port']})
    print(discovered_devices)

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

arduino ESP8266

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiClient.h>
#include <WebSocketsClient.h>

const char* ssid = "ssid";
const char* password = "password ";
const char* serverAddress = "192.168.1.18"; // Replace with your Flask server IP
const int serverPort = 5000; // Use the appropriate port

WiFiClient wifiClient;
WebSocketsClient webSocket;

WiFiServer server(serverPort);

int LED = 5;
String receivedMessage;

void setup() {
  pinMode(LED, OUTPUT);
  Serial.begin(115200);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to WiFi");

  webSocket.begin(serverAddress, serverPort);
  webSocket.onEvent(webSocketEvent);

  // Get the last number of the IP address and use it as the hostname
  String ipString = WiFi.localIP().toString();
  int lastIndex = ipString.lastIndexOf('.');
  String lastNumber = ipString.substring(lastIndex + 1);
  String hostname = "arduino" + lastNumber;

  // Print out the IP address and port
  Serial.println("Arduino IP: " + ipString);
  Serial.println("Arduino Port: " + String(serverPort));

  // Initialize mDNS
  if (!MDNS.begin(hostname.c_str())) {
    Serial.println("Error setting up mDNS");
  } else {
    Serial.println("mDNS responder started with hostname: " + hostname);
  }

  server.begin();
}


void loop() {
  webSocket.loop();
  MDNS.update();
  WiFiClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        receivedMessage = client.readStringUntil('\r');
        Serial.println("Received message: " + receivedMessage);
        // Message processing
        commandBreakDown(receivedMessage);
        client.println(receivedMessage); // Send the received message back to the client
        delay(100);
        client.stop();
      }
    }
  }
}
void commandBreakDown(String message) {
  int spaceIndex = message.indexOf(' ');
  if (spaceIndex != -1) {
    String command = message.substring(0, spaceIndex);  // Extract the command
    // Check if the command is valid
    if (command.equals("C1")) {
      String valueStr = message.substring(spaceIndex + 1);  // Extract the value
      int value = valueStr.toInt();
      digitalWrite(LED, HIGH); // Turn the LED on
      delay(value);
      digitalWrite(LED, LOW); // Turn the LED off
    }
  }
}
//webSocketEvent stuff
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
  String discoveryMessage; // Declare the variable here

  switch(type) {
    case WStype_DISCONNECTED:
      Serial.println("WebSocket disconnected");
      break;
    case WStype_CONNECTED:
      Serial.println("WebSocket connected");
      // Build the discovery JSON object
      discoveryMessage = "{\"hostname\":\"arduino\", \"ip\":\"" + WiFi.localIP().toString() + "\", \"port\":" + String(serverPort) + "}";
      webSocket.sendTXT(discoveryMessage.c_str());
      break;
    case WStype_TEXT:
      Serial.printf("Received payload: %s\n", payload);
      // Handle text payload, if needed
      break;
  }
}

Any advice on how to fix it


Solution

  • I think that's an issue with the WebSocket library that you are using. SocketIO and WebSockets are semi-compatible

    From SocketIO's docs

    Although Socket.IO indeed uses WebSocket for transport when possible, it adds additional metadata to each packet. That is why a WebSocket client will not be able to successfully connect to a Socket.IO server, and a Socket.IO client will not be able to connect to a plain WebSocket server either.

    I think that's the message you are getting in Python effectively saying.

    "This is a webSocket client!" 400 -" ...not a SocketIo client...go away

    I use WebSockets intensively both server/client (Node.js/ESP/Arduino) and it works great (different Arduino library though) but I don't know if that's an option to use native WebSockets or you have to use SocketIO on the server?

    There are some Arduino SocketIO libraries Socket.io-Esp-client no idea how good they are but maybe worth having a look.