[SOLVED] TCPCLIENT intranet connection fails if no cloud connection


#1

Has anyone else found that you need a cloud connection (breathing cyan) when using TCPCLIENT to connect to a service on the local LAN?

It seems that the lack of cloud connection causes the network stack to be reset which then stops TCPCLIENT from working at all. It is only resolved by resetting the Photon.

Am using firmware 0.5.3.rc1


[SOLVED] WiFi Reconnection Issue - Is there a solution?
Intranet only - WiFi disconnects - how to stop?
WiFi channel switching stops WiFi connectivity and is only recoverable by reboot (BUG)
[SOLVED] WiFi Reconnection Issue - Is there a solution?
Intranet only - WiFi disconnects - how to stop?
Particle.connect() disconnects WiFi - can this be stopped?
#2

I’m not seeing that problem. I ran the test program below on a Photon running 0.5.3rc1 and it worked normally. The important thing is that you need to use manual (or probably semi-automatic) system mode and start WiFi, but not the Particle connection.

#include "Particle.h"

SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(MANUAL);

const unsigned long SEND_PERIOD_MS = 20000;

enum WifiState { WIFI_STATE_NOT_CONNECTED, WIFI_STATE_CONNECTING, WIFI_STATE_CONNECTED, WIFI_STATE_RUNNING };

IPAddress serverAddr(192,168,2,4);
const int serverPort = 8080;

WifiState wifiState = WIFI_STATE_NOT_CONNECTED;
unsigned long lastSend = 0;
TCPClient client;
int seq = 0;

void setup() {
	Serial.begin(9600);

	WiFi.on();
}

void loop() {
	switch(wifiState) {
	case WIFI_STATE_NOT_CONNECTED:
		Serial.println("connecting");
		WiFi.connect();
		wifiState = WIFI_STATE_CONNECTING;
		break;

	case WIFI_STATE_CONNECTING:
		if (WiFi.ready()) {
			wifiState = WIFI_STATE_CONNECTED;
		}
		// The WiFi.connect() call never times out, it will keep trying forever so there's
		// no need to call WiFi.connect() again here.
		break;

	case WIFI_STATE_CONNECTED:
		// Do any one-time initialization here like calling udp.begin() or tcpServer.begin()
		Serial.println("connected");
		wifiState = WIFI_STATE_RUNNING;
		break;

	case WIFI_STATE_RUNNING:
		if (!WiFi.ready()) {
			Serial.println("disconnected during connected state");
			wifiState = WIFI_STATE_CONNECTING;

			// No need to call WiFi.connect() again, it will keep retrying forever
			break;
		}

		// Running with WiFi enabled here
		if (millis() - lastSend >=  SEND_PERIOD_MS) {
			lastSend = millis();

			if (client.connect(serverAddr, serverPort)) {
				Serial.printlnf("sending seq=%d", seq);
				client.printlnf("%d\n", seq++);
				client.stop();
			}
			else {
				Serial.println("connection failed");
			}
		}
		break;


	}
}


#3

Thanks @rickkas7!

Am using SYSTEM_MODE(SEMI_AUTOMATIC).

I notice that in your code that you are not calling Particle.process(), so (I think) the Photon will not be trying to connect with the cloud (because you are in MANUAL mode) whereas in my situation, it is trying to connect.

For my use, am wanting to continue trying to connect to the cloud.

Unfortunately I have not got time today to modify your code to test out this situation, but will do so next week and report back.


#4

I think it’s not the presence or absence of a cloud connection that interferes with your TCPClient, but rather your (possibly frequent) reconnection attempts.


#5

I don’t think Particle.process() is the cause because at least with system thread enabled, which you should set, you can call it even when not connected to the cloud and nothing bad happens.

In any case, the situation is different than I interpreted in your original post, and it will take a little longer to set up a test for that. Basically, you have a situation where you always want to connect to a local server, but you may or may not have a connection to the cloud - the cloud Internet link may or may not be up. But you still want to connect to the cloud when it’s available. Right?


#6

@rickkas7, your interpretation of what is wanted is correct.

The network configuration is such that internet connection is mostly not there (because of the client’s security concerns).

I would like to modify your test code to first try and reproduce the fault and then move on from there.

@Scruffr, interesting theory! I will also test this using @rickkas7’s test scaffold.

Good news at least is that our work around was to tell the client “you must allow us to have an internet connection for the application to work”.

Hopefully back next week with some reproducible results.

Cheers - @umd


#7

With or without SYSTEM_THREAD(ENABLED) Particle.process() won’t cause any trouble.
But other commands (e.g. at least Particle.publish() used to) should be wrapped in an
if (Particle.connected()) { ... }


#8

This example should be closer to what you want:

#include "Particle.h"

SYSTEM_THREAD(ENABLED);
SYSTEM_MODE(SEMI_AUTOMATIC);

const unsigned long SEND_PERIOD_MS = 15000;

enum WifiState { WIFI_STATE_NOT_CONNECTED, WIFI_STATE_CONNECTING, WIFI_STATE_CONNECTED, WIFI_STATE_RUNNING };

IPAddress serverAddr(192,168,2,186);
const int serverPort = 8081;

WifiState wifiState = WIFI_STATE_NOT_CONNECTED;
unsigned long lastSend = 0;
TCPClient client;
int seq = 0;

void setup() {
	Serial.begin(9600);

	WiFi.on();
}

void loop() {
	switch(wifiState) {
	case WIFI_STATE_NOT_CONNECTED:
		Serial.println("connecting");
		WiFi.connect();
		wifiState = WIFI_STATE_CONNECTING;
		break;

	case WIFI_STATE_CONNECTING:
		if (WiFi.ready()) {
			wifiState = WIFI_STATE_CONNECTED;
		}
		// The WiFi.connect() call never times out, it will keep trying forever so there's
		// no need to call WiFi.connect() again here.
		break;

	case WIFI_STATE_CONNECTED:
		// Do any one-time initialization here like calling udp.begin() or tcpServer.begin()
		Serial.println("connected");

		// Also connect to the Particle cloud
		Particle.connect();

		wifiState = WIFI_STATE_RUNNING;
		break;

	case WIFI_STATE_RUNNING:
		if (!WiFi.ready()) {
			Serial.println("Wifi disconnected during connected state");
			wifiState = WIFI_STATE_CONNECTING;

			// No need to call WiFi.connect() again, it will keep retrying forever
			break;
		}

		// Running with WiFi enabled here
		if (millis() - lastSend >=  SEND_PERIOD_MS) {
			lastSend = millis();

			Serial.println("about to connect");
			if (client.connect(serverAddr, serverPort)) {
				Serial.printlnf("sending seq=%d", seq);
				client.printlnf("%d\n", seq++);
				client.stop();
			}
			else {
				Serial.println("connection failed");
			}

			if (Particle.connected()) {
				Serial.println("publishing event");
				Particle.publish("test4", "", PRIVATE);
			}
			else {
				Serial.println("not connected to the cloud, skipping publishing event");
			}
		}
		break;

	}

	// System thread enable mode is used so this is not necessary to keep the cloud
	// connection is alive, but it is necessary to handle the system events, including
	// the button, so it's here, regardless of the connection state.
	Particle.process();
}

This worked well for me. It starts up and if there’s a connection to the Internet everything works normally. If you disconnect the Internet the Photon blinks cyan, every few minutes it blinks green for a second, but mostly it just blinks cyan. When you reconnect the Internet it goes back to breathing cyan. Meanwhile, it will continue to make connections to a local server the whole time.

This is not necessarily the simplest example of something that works, but it does work.

Sample output:

sending seq=4
publishing event
about to connect
sending seq=5
publishing event
about to connect
sending seq=6
not connected to the cloud, skipping publishing event
about to connect
sending seq=7
not connected to the cloud, skipping publishing event
Wifi disconnected during connected state
connected
about to connect
sending seq=8
not connected to the cloud, skipping publishing event
about to connect
sending seq=9
publishing event
about to connect
sending seq=10
publishing event

Particle.connect() disconnects WiFi - can this be stopped?
#9

@rickkas7, I took your code and simply added Serial.print("."); to the main loop so that I could test the following scenarios by turning off and on Mobile Network Sharing:Portable Wi-Fi hotspot and Mobile Data on my mobile phone:

a) No WiFi, no Data = “…” <== GOOD
b) WiFi, no Data = "… " & “123, 124” etc on netcat listening session <== GOOD
c) WiFi, Data = "… " & “123, 124” etc on netcat listening session <== expected

So, this looks like a robust solution! Thanks for this.

Hopefully in the next day or so I will be able to get around to folding your code into mine. I will report back on the results of this.

(thanks to @Scruffr too).


#10

@rickkas7, folded your code into my main loop and it works like a charm.

Happy to report - case closed!