1

I'm trying to implement a full-duplex communication between my ESP8266 and a socketserver running on my laptop. In concrete I need each of the devices to initiate communication whenever it needs to. The ESP is measuring temperature all the time and when the temperature changes, I want the ESP to transmit the new temperature to my laptop. On the other side I want to transmit a command from my laptop whenever I want to know the actual temperature (even if the temperature has not changed).

Therefore I have a python server-script and a python client-script both running on my laptop (see scipts below).

In the loop function on my ESP I'm also running a server and a client (script below).

Sending commands from laptop-client to ESP-server works perfectly. Even at high rates and for days without any problem.

Communicating the other way around (that is sending from ESP-client to laptop-server) seems to work in general, but after numerous packages (usually a few hundreds) have been sent from ESP-client to laptop-server the communication fails and the laptop-server only receives empty byte-strings. After that has happened, also sending commands from laptop-client to ESP-server does not work any more temporarily. When I shutdown the laptop-server, the ESP needs some time to "calm down" and will then continue working as usual.

Can anyone imagine what causes this behaviour? To me it looks like a buffer overflow or something like that. I appreciate any help and hints about how to implement the desired functionality (do I actually need to run a server on both my laptop and the ESP?).

Laptop-Server:

import socket
import time

# create a socket object
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

host = "0.0.0.0"
port=1992

# bind to the port
serversocket.bind((host, port))

# queue up to 5 requests
serversocket.listen(5)

try:
  while True:
    # establish a connection
    clientsocket,addr = serversocket.accept()
    try:
        data = clientsocket.recv(1024)
        print(str(addr),":  ",data)
        clientsocket.send("hi there, "+str(addr)+"\n")
        clientsocket.close()
    except:
        pass
except:
  print(" !!! an exception occured !!!")
  serversocket.shutdown(socket.SHUT_RDWR)
  serversocket.close()

Laptop-Client:

import os,sys,re,time,socket,threading,readline

timeout=2

HOST, PORT = "ESP-IP", 1991

response=""
def s_client(data):
    global response
    try:
        response='Error: received no response'

        # Connect to server and send data
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(timeout)
        sock.connect((HOST, PORT))
        sock.sendall(bytes(data + "\n", "utf-8"))

        # Receive data from the server and shut down
        response=str(sock.recv(1024), "utf-8")
    except ConnectionRefusedError:
        response='Error: connection refused by remote host'
    except socket.timeout:
        response='Error: connection timed out'
    finally:
        sock.close()
    return 1


while True:
    try:
        print('  -->  '+s_client(input('_$ ')))
    except KeyboardInterrupt:
        break

ESP-script (containing server and client):

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

IPAddress laptop_ip=(0,0,0,0);
uint16_t TCP_port=1991;
uint16_t TCP_remote_port=1992;
WiFiServer TCPserver(TCP_port);
WiFiClient client;

void ESP_server(void){
  if (!client.connected()) {
    client=TCPserver.available();
  }
  else {
    laptop_ip=client.remoteIP();
    Serial.println("received request");
    int query_l=client.available();
    if(query_l>0){
      String query="";
      for (int nb = 0; nb < query_l-1; nb++){
        query+=(char) client.read();
      }client.read();
      Serial.print("received from laptop: ");Serial.println(query);
      //  Do something with query and return the result
      //  For simplicity I'm just returning a constant value
      client.write("command transmitted");
    }
  }
}

void ESP_client(String message){
  WiFiClient TCPclient;
  if (TCPclient.connect(laptop_ip, TCP_remote_port)){
    TCPclient.print(message);
  }
}


void setup() {
  Serial.begin(115200);
  WiFi.begin("MYSSID","MYPASS");
  Serial.print("connecting with WiFi  ");
  while(WiFi.status()!=WL_CONNECTED){
    Serial.print(".");
    delay(500);
  }Serial.println();
  TCPserver.begin();

  // wait until a command has been received from the laptop
  // ESP_server stores the remote (laptop) ip in laptop_ip
  while(laptop_ip==(0,0,0,0)){
    ESP_server();
  }
}

int temp=0;
void loop() {
  // handle commands sent from my laptop
  ESP_server();

  //  here is a temperature meaurement returning the current temperature
  //  I've replaced it with a temperature generator
  if(temp<30){temp++;}
  else{temp=0;}

  // temperature has changed and needs to be transmitted by this function
  ESP_client((String) temp);
}

The above code differes from the code I'm actually running but it reproduces my problem. I hope that somebody can figure out a misstake or give my some advice about how I could implement things in a better way. Actually I'm not sure whether the misstake is on laptop- or ESP-side but as the ESP crashes sometimes I think it's the ESP...

I'm using the arduino IDE for flashing, btw.

1

close the disconnected socket before reconnecting

if (!client.connected()) {
  client.stop();
  client=TCPserver.available();
}
  • Please excuse my belated response. Unfortunately, that doesn't do the trick... – Sim Son Dec 7 '17 at 20:00
1

I found my stupid mistake: By using try without catching specific exceptions (I know one shouln't do that) in my Laptop-Server script I didn't recognize that I was trying to send unencoded strings. So, clientsocket.send("hi there, "+str(addr)+"\n") has to be clientsocket.send(bytes(("hi there, "+str(addr)+"\n").encode('utf-8'))) instead.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.