Local server in node.js example


#44

You need to set the IP & port of your server via the Particle.function()

You may want to reread the first post to understand the whole setup process and process flow.


#46

Hi, Thank to you, Its working now and I can get the 2 readings from my sensor, As a next step, I want to plot 2 graph lines in different colors from my 2 different reading, any advice on how can i acheive that?
Thank you again for you kind help.


#47

I’d look in this file
https://github.com/rickkas7/localserver/blob/master/livegraph/public/main.js


#48

I’m not sure I understand what you mean by setting the IP/port since a devicesRequest is published and in the setup it initiates the function for devicesHandler? What exactly is missing?


#49

The device needs to know which client to report to in this block

case STATE_CONNECT:
		if (client.connect(serverAddr, serverPort)) {
			client.println("POST /devices HTTP/1.0");
			client.printlnf("Authorization: %s", nonce);
			client.printlnf("Content-Length: 99999999");
		    client.println();
		    state = STATE_SEND_DATA;
		}

How do you think deviceHandler() will set serverAddr, serverPort and nonce and to what values?
Where should these come from?

If everything goes to plan these infos would be supplied by a server that responds to the publish, but if that doesn’t happen for some reason, you can (may need to) do this via a “manual” call to deviceHandler() providing the needed data.


#50

@rickkas7 @ScruffR @Moors7

Hi, I’m still trying to use this example to get my Photon connected to a web server. I’m currently running the web server (through node.js) on my computer, and then trying to connect to this server from a browser on the same computer. That isn’t the issue right?

It seems that I can’t seem to enter the connect if statement below:

case STATE_CONNECT:
	client.connect(serverAddr, serverPort);
	Serial.println(serverAddr);
	Serial.println(serverPort);	

	if (client.connect(serverAddr, serverPort)) {
		client.println("POST /devices HTTP/1.0");
		client.printlnf("Authorization: %s", nonce);
		client.printlnf("Content-Length: 99999999");
	    client.println();
	    state = STATE_SEND_DATA;
	}
	else {
		Serial.println("Entering here");
		state = STATE_RETRY_WAIT;
		Serial.println(client.connect(serverAddr, serverPort));
		stateTime = millis();
	}

This is my serial monitor output:

This is my node.js server output (with a few console print lines):

The proton IP address is 192.168.0.23
It looks to me like the server correctly identifies the proton, and vice versa, but for whatever reason the client.connect statement returns 0 or false. Any ideas??

I also have no output in the javascript console when I access the web server…
I’m running on node v8.9.4, vpm v5.6.


#51

One thing is that you are calling client.connect() twice in the same go. Why is that? In the code snippet provided above it’s only called once.
Do you ever close the connection?
Can you show the rest of your code?


#52

I was calling client.connect() twice just to get it out of the “if statement” and see if I could get any kind of error log back. When I remove that statement, I still get the same output. The only thing I modified in the server code is the “multiple server addresses detected” line - I changed those to use the wifi address instead of the Ethernet address. I can also connect to that web server in my browser. I’ve also tried multiple ports, and tried using an AWS node.js server and still can’t seem to get the photon to connect…

Here is the full firmware code:

#include "Particle.h"

SYSTEM_THREAD(ENABLED);

int devicesHandler(String data); // forward declaration
void sendData(void);

const unsigned long REQUEST_WAIT_MS = 10000;
const unsigned long RETRY_WAIT_MS = 10000;
const unsigned long SEND_WAIT_MS = 40;

// Sensors

/* Assign a unique ID to the sensors */
//Adafruit_10DOF dof;
//Adafruit_LSM303_Accel_Unified accel(30301);
//Adafruit_LSM303_Mag_Unified mag(30302);
//Adafruit_BMP085_Unified bmp(18001);
//float seaLevelPressure = SENSORS_PRESSURE_SEALEVELHPA;

enum State { STATE_REQUEST, STATE_REQUEST_WAIT, STATE_CONNECT, STATE_SEND_DATA, STATE_RETRY_WAIT };
State state = STATE_REQUEST;
unsigned long stateTime = 0;
IPAddress serverAddr;
int serverPort;
char nonce[34];
TCPClient client;
bool sensorsInitialized;

void setup() {
	Serial.begin(9600);
	Particle.function("devices", devicesHandler);

	// Initialize sensors
	//sensorsInitialized = (accel.begin() && mag.begin() && bmp.begin());
}

void loop() {

	switch(state) {
	case STATE_REQUEST:
		if (Particle.connected()) {
			Serial.println("sending devicesRequest");
			Particle.publish("devicesRequest", WiFi.localIP().toString().c_str(), 10, PRIVATE);
			state = STATE_REQUEST_WAIT;
			stateTime = millis();
		}
		break;

	case STATE_REQUEST_WAIT:
		if (millis() - stateTime >= REQUEST_WAIT_MS) {
			state = STATE_RETRY_WAIT;
			stateTime = millis();
		}
		break;

	case STATE_CONNECT:
		//client.connect(serverAddr, serverPort); For debugging
		//Serial.println(serverAddr);
		//Serial.println(serverPort);

		if (client.connect(serverAddr, serverPort)) {
			client.println("POST /devices HTTP/1.0");
			client.printlnf("Authorization: %s", nonce);
			client.printlnf("Content-Length: 99999999");
		    client.println();
		    state = STATE_SEND_DATA;
		}
		else {
			Serial.println("Entering here");
			state = STATE_RETRY_WAIT;
			//Serial.println(client.connect(serverAddr, serverPort)); for debugging - returns 0
			stateTime = millis();
		}
		break;

	case STATE_SEND_DATA:
		// In this state, we send data until we lose the connection to the server for whatever
		// reason. We'll to the server again.
		if (!client.connected()) {
			Serial.println("server disconnected");
			client.stop();
			state = STATE_RETRY_WAIT;
			stateTime = millis();
			break;
		}

		if (millis() - stateTime >= SEND_WAIT_MS) {
			stateTime = millis();

			sendData();
		}
		break;

	case STATE_RETRY_WAIT:
		if (millis() - stateTime >= RETRY_WAIT_MS) {
			state = STATE_REQUEST;
		}
		break;
	}
}

void sendData(void) {
	// Called periodically when connected via TCP to the server to update data.
	// Unlike Particle.publish you can push a very large amount of data through this connection,
	// theoretically up to about 800 Kbytes/sec, but really you should probably shoot for something
	// lower than that, especially with the way connection is being served in the node.js server.
	Serial.println("don't tell me we're here");

	// Taken from the Adafruit 10-DOF example code
	//sensors_event_t accel_event;
	//sensors_event_t mag_event;
	//sensors_event_t bmp_event;
	//sensors_vec_t   orientation;

	// Read the accelerometer and magnetometer
	//accel.getEvent(&accel_event);
	//mag.getEvent(&mag_event);

	// Use the new fusionGetOrientation function to merge accel/mag data
	//if (!dof.fusionGetOrientation(&accel_event, &mag_event, &orientation)) {
		// Failed to get data
	//	return;
	//}
	// float orientation.roll
	// float orientation.pitch
	// float orientation.heading

	// Calculate the altitude using the barometric pressure sensor
	//bmp.getEvent(&bmp_event);
	//if (!bmp_event.pressure) {
		// Failed to get pressure
	//	return;
	//}
	// Get ambient temperature in C
	//float temperature;
	//bmp.getTemperature(&temperature);

	//float altitude = bmp.pressureToAltitude(seaLevelPressure, bmp_event.pressure, temperature);

	// Use printf and manually added a \n here. The server code splits on LF only, and using println/
	// printlnf adds both a CR and LF. It's easier to parse with LF only, and it saves a byte when
	// transmitting.
	//client.printf("%.3f,%.3f,%.3f,%.3f,%.2f,%.1f\n",
	//		orientation.roll, orientation.pitch, orientation.heading,
	//		altitude, bmp_event.pressure, temperature);

	//client.printf("%s\n", 10 );

	// roll,pitch,heading,altitude,pressure,temperature
	// Example:
	// 0.000,-0.449,-49.091,263.317,982.02,27.5
	// -0.224,-0.224,-48.955,262.719,982.09,27.5
	// 0.000,-0.449,-48.704,262.719,982.09,27.5
	// 0.000,-0.449,-48.704,262.890,982.07,27.5
}

int devicesHandler(String data) {
	Serial.printlnf("devicesHandler data=%s", data.c_str());
	int addr[4];

	IPAddress myIP = WiFi.localIP();
	Serial.println(myIP);    // prints the device's IP address

	if (sscanf(data, "%u.%u.%u.%u,%u,%32s", &addr[0], &addr[1], &addr[2], &addr[3], &serverPort, nonce) == 6) {
		serverAddr = IPAddress(addr[0], addr[1], addr[2], addr[3]);
		Serial.printlnf("serverAddr=%s serverPort=%u nonce=%s", serverAddr.toString().c_str(), serverPort, nonce);
		state = STATE_CONNECT;
	}
	return 0;
}

#53

Do you have port 8070 open on your Windows firewall? The node.js server will listen even if blocked, and you’ll probably be able to connect from a web browser on the same computer, but the Photon wouldn’t be able to connect.


#54

Hi rickkas, I’m triying yo use your good example but I have the problem of the accesstoken. So I create a txt file with the token (from build.particle.io), but now the console is showing “unable to open settings”. I have the particle-api-js version 7.1.1. Could you help me with this? Thank you so much.


#55

Any idea how to send data to the Photon. I have some parameters (PID controller) I would like to be able to enter in the webbrowser and send to Photon while monitoring the effect on the measured value send from the Photon.


#56

There are tutorials that show how that is done via Particle.function() or Particle.subscribe() (previously Spark.xxxx()) in the Tutorials section.

Or even in the docs
https://docs.particle.io/reference/javascript/
https://docs.particle.io/reference/javascript/#callfunction
https://docs.particle.io/reference/javascript/#publishing-event