Photon crashes with TCPServer and no internet connection


#1

Hi,

I have the following code:
Which works great and stable, when there is internet on the router (the wan cable is plugged), but when I disconnect the WAN cable from the router, the photon starts to crash after 5-10 sec (red blinks), and then restarts, then again works for 5-10 sec, then restarts.
Why is that?

SYSTEM_THREAD(ENABLED);

TCPServer server = TCPServer(3456);
TCPClient client;
unsigned long last_send = 0;
unsigned long last_blink = 0;
unsigned long blink_interval = 100;
bool blink_state = false;
int led = D7;

void setup() {
    pinMode(led, OUTPUT);
    server.begin();
    Serial.begin(115200);
    print_data();
}


void loop() {
    if (millis() - last_blink > blink_interval) {
        last_blink = millis();
        blink_state = !blink_state;
        digitalWrite(led, blink_state);
    }

    if (Serial.available()) {
        Serial.println(millis());
        while (Serial.available()) {
            Serial.read();
        }
        print_data();
        Serial.println(millis());
    }

    if (millis() - last_send >= 100) {
        IPAddress myAddr = WiFi.localIP();
        if (myAddr[0] == 192 && myAddr[1] == 168 && myAddr[2] == 1 && myAddr[3] == 111) {
            // photon is connected to the router and got the right IP
            blink_interval = 200;
        } else {
            // not connected 
            blink_interval = 1000;
        }
        IPAddress clientIP = client.remoteIP();
        //Serial.println(clientIP);

        if (clientIP[0] == 0 && clientIP[1] == 0 && clientIP[2] == 0 && clientIP[3] == 0) {

        } else {
            // a client is connected to photon
            blink_interval = 20;
        }

 
        unsigned long temp = millis();
        last_send = temp / 100 * 100;
  
        server.printf("%lu: {test}", temp);
 
    }

    if (client.connected()) {
        if (client.available()) {
            Serial.print(millis());
            Serial.print(": ");
            while (client.available()) {
                Serial.write(client.read());
            }
            Serial.println();
        }

    } else {
        client = server.available();
    }
}

void print_data() {

    Serial.println(WiFi.localIP());
    Serial.println(WiFi.subnetMask());
    Serial.println(WiFi.gatewayIP());
    Serial.println(WiFi.SSID());
    byte mac[6];
    WiFi.macAddress(mac);

    for (int i = 0; i < 6; i++) {
        Serial.printf("%02x%s", mac[i], i != 5 ? ":" : "");
    }
}

#2

Since you are using default AUTOMATIC mode the device OS will keep trying to reestablish the cloud connection which has to fail without WAN and may interfere with your TCP connection.

Try SYSTEM_MODE(SEMI_AUTOMATIC) or SYSTEM_MODE(MANUAL) and make sure to call Particle.disconnect() when your WAN goes away.

You should also not use client without making sure it was initialised.
And if a previously valid client becomes disconnected you should call client.stop() before acquiring a new socket.


#3

Thanks for your quick response!

"Try SYSTEM_MODE(SEMI_AUTOMATIC) or SYSTEM_MODE(MANUAL) and make sure to call Particle.disconnect() when your WAN goes away."
I would like to keep automatic, and if there is no internet, the system can keep trying the connect again and again, but not crashing the system. This is how it is done normalliy only crashes with tcp server code…
Can you please show as a safe and proper code for that? I have used the codes from particles examples… But in the other hand I do no understand, how is it possible that a system/firmware crashes on an an external factor event. This error should be handled in firmware level I guess…

"You should also not use client without making sure it was initialised."
That is also clear, but I have used the example from particles site. So what is the proper way?

"And if a previously valid client becomes disconnected you should call client.stop() before acquiring a new socket."
As my understanding I modified my code: Is it ok like that?

 if (client.connected()) {
        client_connected = true;
        if (client.available()) {
            Serial.print(millis());
            Serial.print(": ");
            while (client.available()) {
                Serial.write(client.read());
            }
            Serial.println();
        }

    } else {
        if (client_connected == true) {
            client_connected = false;
            client.stop();
        }
        client = server.available();
    }

Thank you very much for your help!!!


#4

Anyone else can help me?
I have choose particle for my project because it is easy to use could solution, but does not work the cloud and tcpserver stable enough (at the same time)… :frowning:

Thank you very much!


#5

When you are in automatic mode, the device OS will try as hard as it can to reconnect to the Particle cloud to the point where it will reset the device the eventually if it cannot connect. You do not seem to want to that behavior and the only way to avoid it is using semi-automatic mode or manual mode.


#6

This is what I thought, but …

… since that was out of question I don’t think we can’t do much :speak_no_evil:


#7

Thank you for the answers. Yes, I tried with SEMI_AUTOMATIC or even with MANUAL.
But the photon restarts if there is no WAN.
I have got the recommendation that I have to check if the router has connected to the WAN and has internet or not, but how can I do that?

Are there any other hidden requirements that photon needs to work properly? Like I can place only in a blue box? or has to be an Ikea chair at least 43 cm from the photon?

I just do not get the point why a micro-controller restarts every 10 sec, because of an external factor on which we do not have any control of…


#8

All I can tell is many other people have gotten this to work fine. Sarcasm helps no one here.


#9

Thank for your answer.
I am sorry if I hurt your feelings, I did not meant as a sarcasm, I meant more like criticism which can help to make the product better.

Unfortunately two of your statements are misleading/half true/false
1.
"When you are in automatic mode, the device OS will try as hard as it can to reconnect to the Particle cloud to the point where it will reset the device the eventually if it cannot connect."
The device restarts with SOS blink pattern, which is the signal of the crash of the firmware, and not the firmware has restarted the photon on purpose because of no cloud connection, but because of the crash
2.
"All I can tell is many other people have gotten this to work fine."
This is probably because the “many other people” have not tested enough, and after 2 minutes of testing they just made a conclusion that is working stable,
and everybody else just looser.

I have tried with a very basic code:


SYSTEM_THREAD(ENABLED);

TCPServer server = TCPServer(3456);
TCPClient client;

void setup()
{
  server.begin();


  Serial.begin(9600);

  Serial.println(WiFi.localIP());
  Serial.println(WiFi.subnetMask());
  Serial.println(WiFi.gatewayIP());
  Serial.println(WiFi.SSID());
}

void loop()
{
  if (client.connected()) {
    // echo all available bytes back to the client
    while (client.available()) {
      server.write(client.read());
    }
  } else {
    // if no client is yet connected, check for a new connection
    client = server.available();
  }
}

scenario:
There is internet AND client is connected to the server: WORKS
There is NO internet AND client is NOT connected to the server: WORKS
There is NO internet AND client is connected to the server: CRASHES every 10 sec

If I comment out the SYSTEM_THREAD(ENABLED); then working again without crash.

So, the conclusion is that if you run out of Christmas tree lights all you have to do is grab a photon, run the following code, connect to the server and disconnect wan from the router… :slight_smile:

However, I really appreciate your and ScruffR inputs! I hope Particles team will fix this random feature soon…


#10

Can you PM the server code (or a stripped down version) in order to test exactly your setup on one of my devices?

I’d think this should be solvable.


#11

I think you meant the client code:

import UIKit
import Foundation
import SystemConfiguration.CaptiveNetwork


class ViewController: UIViewController {
    let formatter = DateFormatter()
    let client = TCPClient(address: "192.168.1.111", port: 3456)
    
    var lastWIFICommunication: Double = 0
    var counter: Double = 0
    var wifiListener: Timer!
    var Timestamp: Double {
        return Date().timeIntervalSince1970 * 1000
    }
    var sampleTextField = UITextField(frame: CGRect(x: 20, y: 100, width: 300, height: 40))
    
    
    func getWiFiSsid() -> String? {
        var ssid: String?
        if let interfaces = CNCopySupportedInterfaces() as NSArray? {
            for interface in interfaces {
                if let interfaceInfo = CNCopyCurrentNetworkInfo(interface as! CFString) as NSDictionary? {
                    ssid = interfaceInfo[kCNNetworkInfoKeySSID as String] as? String
                    break
                }
            }
        }
        return ssid
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        connect()
        _ = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(ViewController.checkconnection), userInfo: nil, repeats: true)
        sampleTextField =  UITextField(frame: CGRect(x: 20, y: 100, width: 300, height: 40))
        sampleTextField.font = UIFont.systemFont(ofSize: 15)
        sampleTextField.borderStyle = UITextBorderStyle.roundedRect
        sampleTextField.autocorrectionType = UITextAutocorrectionType.no
        sampleTextField.keyboardType = UIKeyboardType.default
        sampleTextField.returnKeyType = UIReturnKeyType.done
        sampleTextField.clearButtonMode = UITextFieldViewMode.whileEditing;
        sampleTextField.contentVerticalAlignment = UIControlContentVerticalAlignment.center
        //sampleTextField.delegate = self as! UITextFieldDelegate
        self.view.addSubview(sampleTextField)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    @objc func checkconnection() {
       sampleTextField.text = getWiFiSsid()
  
        var  lol:Double = Timestamp-lastWIFICommunication

        
        if (lol > 5000) {
            print("reconnect")

            if wifiListener != nil {
                wifiListener!.invalidate()
                wifiListener = nil
            }
            client.close()
            connect()
        }
    }
    
    @objc func sayHello()
    {
        
        guard let data = client.read(1024*10) else { return }

        if let response = String(bytes: data, encoding: .utf8) {
            if (response != "-1") {
                client.send(string: response )
                lastWIFICommunication = Timestamp
                print(formatter.string(from: Date()), " ", terminator:"")
                print(response, " length: ",response.count)
            }
            
        }
    }
    func connect() {
        //let client = TCPClient(address: "192.168.1.111", port: 3456)
        formatter.dateFormat = "HH:mm:ss.SSS"
        
        switch client.connect(timeout: 1) {
        case .success:
            //print("lol")
            //print(client.address)
            if wifiListener == nil {
                wifiListener = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(ViewController.sayHello), userInfo: nil, repeats: true)
            }
            
            
            
            switch client.send(string: "GET / HTTP/1.0" ) {
            case .success:
                guard let data = client.read(1024*10) else { return }
                
                // if let response = String(bytes: data, encoding: .utf8) {
                //    print(response)
            // }
            case .failure(let error):
                print(error)
            }
        case .failure(let error):
            print(error)
        }
    }


}

But if you try with any tcp utility (like TCP Utility from app store if you use mac) I think you will get the same result.

Thank you for your time!


#12

Do you have any feedback for me?

Thank you!


#13

Sorry, I didn’t have any chance to deeper look into it yet. I’ve setup the test rig, but never got round to actually testing.


#14

Ok, no problem, you helped me already a lot! :slight_smile:


#15

Did you guys see this thread?

I too had problems with stability when using TCPServer on an connection with intermittent WiFi or WAN.

At the very end of the thread there’s discussion of disabling SYSTEM_FLAG_RESET_NETWORK_ON_CLOUD_ERRORS and that seems to be the ticket for me (with my app running on 0.7.0).


#16

Thank you so much! I will try!


#17

Thanks to @Elco for digging this up.