Spark resetting Client Server Wifi

Hi,

I’ve been struggling with my spark cores trying to avoid them resetting, assumed to be generally if the connection to the cloud is lost with a simple client / server connection to my pc on the same network.

My goal was for the pc server to regularly (minutes / seconds) ‘poll’ the spark core (‘writing’ a predefined ascii string) and for the core to reply with some status (I had an idea of creating a remote temperature / humidity sensor for my caravan).
I got the DHT11 sensor working, but to rule that out, ive stripped that code from the software, just leaving the client / server basics.

Prior to this, even connecting using the local serial port, the core would still reset if connection to the cloud was lost, so I added code to turn off the cloud connection after a few minutes. Resetting the core would re enable the connection to allow me to download new code. Not ideal, but a workaround. This sorted this issue.

However, with reference to the code example below, this still regularly resets, and the server looses the connection to the core, the only way to reset it is to disable and restart the connection on the server and to reset the core. This does not happen in a regular way like when the DNS on the router is renewed. In fact, my router has a setting to fix the DHCP address given to a device, and to not renew it. So thats ruled out.

I took on advise from various threads on the core resetting and added these to my code, but to no avail.
Note, the counters and other variables were placed in the code to try and work out at what point it resets, and what happens. It appears the entire core resets as the counter starts at 0 (if that makes sense).

Can anyone help with this?

The pseudo code is:

Start
loop
check for server connected and data available
receive incoming string and check against defined value
If incoming string matches, send other strings, variables and data back to the server
repeat

The actual code:

char inbyte[2];
int counter = 0;
int simulate_temp = 21;
unsigned long lastTime = millis();
long disconnect_counter = 0;
int Disconnect_Coms = 0;

// telnet defaults to port 23
TCPServer server = TCPServer(23);
IPAddress localIP = WiFi.localIP();
TCPClient client;

void setup()
{
  server.begin();
  counter == counter + 10;
  //simulate_temp = 30;
}

void loop()
{

  if (client.connected()) 
  {
    while( client.available()==0 && millis()-lastTime<1000) 
    { //3 second timeout
    }  //do nothing
    lastTime = millis();
    
    while( client.available() && millis()-lastTime<1000 ) 
    {  //3 second timeout
        if (client.available()) 
        {
            inbyte[1] = client.read();
            if (inbyte[1] == 'x')
            {
                server.print(WiFi.localIP());
                server.print(",");
                server.print(counter);
                server.print(",");
                server.print(Disconnect_Coms);
                server.print(",");
                server.print(simulate_temp);
                server.print(",");
                server.print(3);
                server.print(",");
                server.print(4);
                server.println("/e");
                counter = counter + 1;
            }
            lastTime = millis();  //reset the timeout only if there was data 
        } 
        else delay(10);  //slow it down a tad, we are waiting anyway
    }
  } 
  
  else 
  {
    client = server.available();
  }
  
  disconnect_counter = disconnect_counter + 1;

    if (disconnect_counter >= 20000)
    {
        if (Disconnect_Coms == 0)
            {
            Spark.disconnect();
            //WiFi.disconnect();
            //WiFi.off();
            Disconnect_Coms = 1;
            }
        disconnect_counter = 20000;
    }
  
}

@jon1977, here is a telnet to serial program I wrote which includes a timeout for client connection since client.connected() is not reliable on the Photon and not sure on the Core. Our code is similar in intent but differ in implementation. If you remove the Serial stuff, you can easily adapt the code for your application. Let me now how it goes :smile:

#include "application.h"

// serial connection
int serialBaud = 9600;

// socket parameters
int serverPort = 23;

// start TCP servers
TCPServer server = TCPServer(serverPort);
TCPClient client;

char myIpString[24];

enum tnetState {DISCONNECTED, CONNECTED};
int telnetState = DISCONNECTED;

unsigned long activity_timeout = 0;
    
void setup() {
    Serial.begin(serialBaud); // open serial communications
    server.begin(); // begin listening for TCP connections

    IPAddress myIP = WiFi.localIP();
    sprintf(myIpString, "%d.%d.%d.%d", myIP[0], myIP[1], myIP[2], myIP[3]);
    Spark.variable("devIP", myIpString, STRING);

}

void loop() {
    
    if (client.connected()) {
        if (telnetState == DISCONNECTED)
            Serial.println("client connected");    //Check for new connection on next loop()

        telnetState = CONNECTED;
        // echo all available bytes back to the client
        int incomingByte = 0;
        while (client.available()) {    //Read incoming TCP data if available and copy to Serial port
            incomingByte = client.read();
            Serial.write(char(incomingByte));
            activity_timeout = millis();
        }
        if (incomingByte != 0)            //Make sure to flush outgoing serial data before looking at serial input
            Serial.flush();

        else if (millis() - activity_timeout > 60000UL) {    // No data received so check 1 minute inactivity timeout
            Serial.println("client.stop");    //Check for new connection on next loop()
            client.stop();
            telnetState = DISCONNECTED;
        }

        while (Serial.available() > 0) {     //Read incoming serial data if available and copy to TCP port
            incomingByte = Serial.read();
            client.write((char)incomingByte);     // write the char data to the client
        }
    }
    else {
        // if no client is yet connected, check for a new connection
        if (telnetState == CONNECTED) {        //If client WAS connected before, so stop() to close connection
            Serial.println("client.stop");    //Check for new connection on next loop()
            client.stop();
            telnetState = DISCONNECTED;
        }
        client = server.available();        //Update TCP client status - "client" is declared globally
    }
}
1 Like

Hi,
I’ve been tinkering with this for a few days now, but its still not working. The core still resets multiple times per day.
I commented out all the serial bits, and added my check for a “x”, then returning an incrementing counter,

I assume it should be possible for the core to site there running its main loop, irrespective of a connection to wifi or the cloud? Resetting just due to a presumed lost connection is causing me issues!

Can anyone see what I’m doing wrong?

With thanks

Jon

Current code:

#include "application.h"

// serial connection
//int serialBaud = 9600;

// socket parameters
int serverPort = 23;
char inbyte[2];
int counter = 0;
int simulate_temp = 21;

// start TCP servers
TCPServer server = TCPServer(serverPort);
TCPClient client;

char myIpString[24];

enum tnetState {DISCONNECTED, CONNECTED};
int telnetState = DISCONNECTED;

unsigned long activity_timeout = 0;
    
void setup() {
    //Serial.begin(serialBaud); // open serial communications
    server.begin(); // begin listening for TCP connections

    IPAddress myIP = WiFi.localIP();
    sprintf(myIpString, "%d.%d.%d.%d", myIP[0], myIP[1], myIP[2], myIP[3]);
    Spark.variable("devIP", myIpString, STRING);

}

void loop() {
    
    if (client.connected()) {
        if (telnetState == DISCONNECTED)
            //Serial.println("client connected");    //Check for new connection on next loop()

        telnetState = CONNECTED;
        // echo all available bytes back to the client
        int incomingByte = 0;
        while (client.available()) {    //Read incoming TCP data if available and copy to Serial port
            //incomingByte = client.read();
            //Serial.write(char(incomingByte));
            inbyte[1] = client.read();
            if (inbyte[1] == 'x')
            {
                server.print(WiFi.localIP());
                server.print(",");
                server.print(counter);
                server.print(",");
                server.print(2);
                server.print(",");
                server.print(simulate_temp);
                server.print(",");
                server.print(3);
                server.print(",");
                server.print(4);
                server.println("/e");
                counter = counter + 1;
            }
            activity_timeout = millis();
        }
        if (incomingByte != 0)            //Make sure to flush outgoing serial data before looking at serial input
            {
                //nothing
            }
            //Serial.flush();
            //client.flush();

        else if (millis() - activity_timeout > 60000UL) {    // No data received so check 1 minute inactivity timeout
            //Serial.println("client.stop");    //Check for new connection on next loop()
            client.stop();
            telnetState = DISCONNECTED;
        }

        //while (Serial.available() > 0) {     //Read incoming serial data if available and copy to TCP port
        //    incomingByte = Serial.read();
        //    client.write((char)incomingByte);     // write the char data to the client
        //}
    }
    else {
        // if no client is yet connected, check for a new connection
        if (telnetState == CONNECTED) {        //If client WAS connected before, so stop() to close connection
            //Serial.println("client.stop");    //Check for new connection on next loop()
            client.stop();
            telnetState = DISCONNECTED;
        }
        client = server.available();        //Update TCP client status - "client" is declared globally
    }
}

@jon1977, there are few glitches in your adaptation:

  1. Why do you have inbyte[2] but only use inbyte[1] in your code.
  2. When you comment out the second line of an “if”, the next line will be used as the conditional portion. You need to comment out the if as well.
  3. The purpose of incomingByte is to check if a char has been received in order to reset the timer. That logic no longer works since you don’t use incomingByte to receive the data.
  4. You should use server.write() instead of print since print() sends a packet for every call. You can build your message and send it in its entirety instead. I used sprintf() to build the outgoing message.

Here is the new (untested) code:

// socket parameters
int serverPort = 23;
char inbyte[2];
int counter = 0;
int simulate_temp = 21;

// start TCP servers
TCPServer server = TCPServer(serverPort);
TCPClient client;

char myIpString[24];
char outmsg[50];


enum tnetState {DISCONNECTED, CONNECTED};
int telnetState = DISCONNECTED;

unsigned long activity_timeout = 0;
    
void setup() {
    //Serial.begin(serialBaud); // open serial communications
    server.begin(); // begin listening for TCP connections

    IPAddress myIP = WiFi.localIP();
    sprintf(myIpString, "%d.%d.%d.%d", myIP[0], myIP[1], myIP[2], myIP[3]);
    Spark.variable("devIP", myIpString, STRING);
}

void loop() {
	
    if (client.connected()) {

        telnetState = CONNECTED;
        // echo all available bytes back to the client
        inbyte[1] = 0;		//set to 0 so can detect when a char is received
        while (client.available()) {    //Read incoming TCP data if available and copy to Serial port
            inbyte[1] = client.read();
            if (inbyte[1] == 'x')
            {
				sprintf(outmsg, "%d.%d.%d.%d,%d,2,%d,3,4/e", myIP[0], myIP[1], myIP[2], myIP[3],counter,simulate_temp)
				server.write(outmsg, strlen(outmsg));
/*
                server.print(WiFi.localIP());
                server.print(",");
                server.print(counter);
                server.print(",");
                server.print(2);
                server.print(",");
                server.print(simulate_temp);
                server.print(",");
                server.print(3);
                server.print(",");
                server.print(4);
                server.println("/e");
*/
                counter = counter + 1;
            }
            activity_timeout = millis();
        }

        if ( inbyte[1] == 0 && (millis() - activity_timeout > 60000UL) ) {    // No data received so check 1 minute inactivity timeout
            //Serial.println("client.stop");    //Check for new connection on next loop()
            client.stop();
            telnetState = DISCONNECTED;
        }

    }
    else {
        // if no client is yet connected, check for a new connection
        if (telnetState == CONNECTED) {        //If client WAS connected before, so stop() to close connection
            //Serial.println("client.stop");    //Check for new connection on next loop()
            client.stop();
            telnetState = DISCONNECTED;
        }
        client = server.available();        //Update TCP client status - "client" is declared globally
    }
}

Hopefully that will work better. Remember that once the client connection is lost, it should not re-attempt to connect until the timeout occurs since I am not sure client.connected() will return false if the connection is dropped. :smile:

Thanks for the prompt response!

  1. I thought you had to declare an array big enough for the zero byte at the end of a string, hence always +1 bytes?
  2. guilty as charged!
  3. Again, guilty as charged.
  4. I’ve corrected a couple of typo’s, new code attached, but I’m struggling with line 43.
    I’m getting the build error:
    test_server_3.cpp:43:38: error: invalid conversion from ‘char*’ to ‘const uint8_t* {aka const unsigned char*}’ [-fpermissive]
    If I comment out line 43, the code verifies ok.
    I can’t find the command strlen in the docs or sprintf, I note in some posts that support for sprintf has been removed?

It looks to be something to do with the variable type in the strlen command expecting uint8_t, but they are defined as int and char.
If I change them all to uint8_t, the build verify also fails.

Any idea where I’m going wrong?

// socket parameters
int serverPort = 23;
char inbyte[1];
int counter = 0;
int simulate_temp = 21;
IPAddress myIP;


// start TCP servers
TCPServer server = TCPServer(serverPort);
TCPClient client;

char myIpString[24];
char outmsg[50];


enum tnetState {DISCONNECTED, CONNECTED};
int telnetState = DISCONNECTED;

unsigned long activity_timeout = 0;
    
void setup() 
{
    //Serial.begin(serialBaud); // open serial communications
    server.begin(); // begin listening for TCP connections

    IPAddress myIP = WiFi.localIP();
    sprintf(myIpString, "%d.%d.%d.%d", myIP[0], myIP[1], myIP[2], myIP[3]);
    Spark.variable("devIP", myIpString, STRING);
}

void loop() 
{
    
    if (client.connected()) 
    {
    telnetState = CONNECTED;
    // echo all available bytes back to the client
    inbyte[1] = 0;        //set to 0 so can detect when a char is received
    while (client.available()) 
        {    //Read incoming TCP data if available and copy to Serial port
            inbyte[1] = client.read();
            if (inbyte[1] == 'x')
            {
                sprintf(outmsg, "%d.%d.%d.%d,%d,2,%d,3,4/e", myIP[0], myIP[1], myIP[2], myIP[3],counter,simulate_temp);
                server.write(outmsg,strlen(outmsg));
                counter = counter + 1;
            }
            activity_timeout = millis();
        }

        if ( inbyte[1] == 0 && (millis() - activity_timeout > 60000UL) ) 
        {    // No data received so check 1 minute inactivity timeout
            //Serial.println("client.stop");    //Check for new connection on next loop()
            client.stop();
            telnetState = DISCONNECTED;
        }

    }
    else 
    {
        // if no client is yet connected, check for a new connection
        if (telnetState == CONNECTED) 
        {        
            //If client WAS connected before, so stop() to close connection
            //Serial.println("client.stop");    //Check for new connection on next loop()
            client.stop();
            telnetState = DISCONNECTED;
        }
    client = server.available();        //Update TCP client status - "client" is declared globally
    }
}

Thanks again
Jon

@jon1977, when you post code, precede and follow (on separate lines) your code with 3 single quotes (below the tilde on the key just left of the “1” key on a keyboard).

  • client.read() does not return a string, just an int value. So no need for an array.
  • I added a function that the very smart @Hootie81 wrote a while back to solve this problem
  • Here is the updated code with changes to make inbyte a non-array var.
// socket parameters
int serverPort = 23;
char inbyte;
int counter = 0;
int simulate_temp = 21;
IPAddress myIP;


// start TCP servers
TCPServer server = TCPServer(serverPort);
TCPClient client;

char myIpString[24];
char outmsg[50];


enum tnetState {DISCONNECTED, CONNECTED};
int telnetState = DISCONNECTED;

unsigned long activity_timeout = 0;

void out(const char *s) {server.write( (const uint8_t*)s, strlen(s) );}


void setup() 
{
    //Serial.begin(serialBaud); // open serial communications
    server.begin(); // begin listening for TCP connections

    IPAddress myIP = WiFi.localIP();
    sprintf(myIpString, "%d.%d.%d.%d", myIP[0], myIP[1], myIP[2], myIP[3]);
    Spark.variable("devIP", myIpString, STRING);
}


void loop() 
{
    
    if (client.connected()) 
    {
    telnetState = CONNECTED;
    // echo all available bytes back to the client
    inbyte = 0;        //set to 0 so can detect when a char is received
    while (client.available()) 
        {    //Read incoming TCP data if available and copy to Serial port
            inbyte = client.read();
            if (inbyte == 'x')
            {
                sprintf(outmsg, "%d.%d.%d.%d,%d,2,%d,3,4/e", myIP[0], myIP[1], myIP[2], myIP[3],counter,simulate_temp);
                out(outmsg);
                counter = counter + 1;
            }
            activity_timeout = millis();
        }

        if ( inbyte == 0 && (millis() - activity_timeout > 60000UL) ) 
        {    // No data received so check 1 minute inactivity timeout
            //Serial.println("client.stop");    //Check for new connection on next loop()
            client.stop();
            telnetState = DISCONNECTED;
        }

    }
    else 
    {
        // if no client is yet connected, check for a new connection
        if (telnetState == CONNECTED) 
        {        
            //If client WAS connected before, so stop() to close connection
            //Serial.println("client.stop");    //Check for new connection on next loop()
            client.stop();
            telnetState = DISCONNECTED;
        }
    client = server.available();        //Update TCP client status - "client" is declared globally
    }
}
2 Likes

Thanks.
I’ve modified slightly to get it verified and functional (also adding an LED toggle so I can see the request from the server).
The counter is now incrementing on my server, so time will tell if it crashes or resets!

Code copied below for reference.

// socket parameters
int serverPort = 23;
char inbyte;
int counter = 0;
int simulate_temp = 21;


// start TCP servers
TCPServer server = TCPServer(serverPort);
TCPClient client;

char myIpString[24];
char outmsg[50];


enum tnetState {DISCONNECTED, CONNECTED};
int telnetState = DISCONNECTED;

unsigned long activity_timeout = 0;

void out(const char *s) {server.write( (const uint8_t*)s, strlen(s) );}

int LED = D7;                      // LED is connected to D7

void setup() 
{
    //Serial.begin(serialBaud); // open serial communications
    server.begin(); // begin listening for TCP connections

    IPAddress myIP = WiFi.localIP();
    sprintf(myIpString, "%d.%d.%d.%d", myIP[0], myIP[1], myIP[2], myIP[3]);
    Spark.variable("devIP", myIpString, STRING);
    pinMode(LED, OUTPUT);            // sets LED pin as output
}


void loop() 
{
    
    if (client.connected()) 
    {
        telnetState = CONNECTED;
        // echo all available bytes back to the client
        inbyte = 0;        //set to 0 so can detect when a char is received
        while (client.available()) 
        {    //Read incoming TCP data if available and copy to Serial port
            inbyte = client.read();
            if (inbyte == 'x')
            {
                digitalWrite(LED, 1);          // Flashes the LED
                delay(500);
                digitalWrite(LED, 0);          // Flashes the LED
                IPAddress myIP = WiFi.localIP();
                sprintf(outmsg, "%d.%d.%d.%d,%d,2,%d,3,4/e", myIP[0], myIP[1], myIP[2], myIP[3],counter,simulate_temp);
                counter = counter + 1;
                out(outmsg);
            }
            activity_timeout = millis();
        }

        if ( inbyte == 0 && (millis() - activity_timeout > 60000UL) ) 
        {    
            // No data received so check 1 minute inactivity timeout
            //Serial.println("client.stop");    //Check for new connection on next loop()
            client.stop();
            telnetState = DISCONNECTED;
        }

    }
    else 
    {
        // if no client is yet connected, check for a new connection
        if (telnetState == CONNECTED) 
        {        
            //If client WAS connected before, so stop() to close connection
            //Serial.println("client.stop");    //Check for new connection on next loop()
            client.stop();
            telnetState = DISCONNECTED;
        }
        client = server.available();        //Update TCP client status - "client" is declared globally
    }
}
1 Like

Just an update. Its been running for over a week now without a glitch.
I had to amend the code to change the:
client.stop();
to
client.flush();
as my server was wanting to be constantly connected. It seemed to get very confused if the client stopped the connection.

Full code copied below in case it helps anyone else:
Features are:

  1. wait for a Telnet string from a server
  2. if it matches a predetermined string, send concatenated data back to the server
  3. in this case, this links to a DHT11 temperature / temperature sensor
    this is basically used to report temperature and humidity repetitively to a server.
//DHT
#include "PietteTech_DHT/PietteTech_DHT.h"
#define DHTTYPE  DHT11       // Sensor type DHT11/21/22/AM2301/AM2302
#define DHTPIN   4           // Digital pin for communications

//declaration
void dht_wrapper(); // must be declared before the lib initialization

// Lib instantiate
PietteTech_DHT DHT(DHTPIN, DHTTYPE, dht_wrapper);

// socket parameters
int serverPort = 23;
char inbyte;
int counter = 0;

// start TCP servers
TCPServer server = TCPServer(serverPort);
TCPClient client;

char myIpString[24];
char outmsg[100];


enum tnetState {DISCONNECTED, CONNECTED};
int telnetState = DISCONNECTED;

unsigned long activity_timeout = 0;

void out(const char *s) {server.write( (const uint8_t*)s, strlen(s) );}

int LED = D7;                      // LED is connected to D7

void setup() 
{
    server.begin(); // begin listening for TCP connections

    IPAddress myIP = WiFi.localIP();
    sprintf(myIpString, "%d.%d.%d.%d", myIP[0], myIP[1], myIP[2], myIP[3]);
    Spark.variable("devIP", myIpString, STRING);
    pinMode(LED, OUTPUT);            // sets LED pin as output
}

void dht_wrapper() {
    DHT.isrCallback();
}

void loop() 
{
    
    if (client.connected()) 
    {
        telnetState = CONNECTED;
        // echo all available bytes back to the client
        inbyte = 0;        //set to 0 so can detect when a char is received
        while (client.available()) 
        {    //Read incoming TCP data if available and copy to Serial port
            inbyte = client.read();
            if (inbyte == 'x')
            {
                int result = DHT.acquireAndWait();
                digitalWrite(LED, 1);          // Flashes the LED
                delay(500);
                digitalWrite(LED, 0);          // Flashes the LED
                IPAddress myIP = WiFi.localIP();
                sprintf(outmsg, "%d.%d.%d.%d,%d,%.2f,%.2f,%.2f,%.2f/e", myIP[0], myIP[1], myIP[2], myIP[3],counter,DHT.getHumidity(),DHT.getCelsius(),DHT.getDewPoint(),DHT.getDewPointSlow());
                counter = counter + 1;
                out(outmsg);
            }
            activity_timeout = millis();
        }

        if ( inbyte == 0 && (millis() - activity_timeout > 60000UL) ) 
        {    
            // No data received so check 1 minute inactivity timeout
            client.flush();
        }

    }
    else 
    {
        // if no client is yet connected, check for a new connection
        if (telnetState == CONNECTED) 
        {        
            client.stop();
            telnetState = DISCONNECTED;
        }
        client = server.available();        //Update TCP client status - "client" is declared globally
    }
}
2 Likes