Read sensor data using ESP8266 on Arduino IDE

Hello!
I have a pulse sensor connected to A0 of an ESP8266 Huzzah board.
I want to send the sensor data to a node.js server.

In the final version of this, I will be deploying everything on a local server without internet so I don't want to use ThingSpeak or other internet-based servers.

I'm having trouble figuring out how to access the sensor data from the server. The data comes in on A0 and is processed so that it goes out serially:

pulseSensor.outputSample(); // returns Sensors, SensorCount

I've combined two example codes, from the pulse sensor examples and from an excellent ESP8266 example found here: www.diyprojects.io

Here's the node.js server

/*
*   Test server
*   http://www.projetsdiy.fr
*/
var express = require('express');
var moment = require('moment');
var app = express();

app.get('/', function(req, res) {
  res.send('HTTP ESP8266 Test Server')
});

app.post('/api/users', function(req, res) {
   // not sure what goes here
    res.send(''); // or here
});

app.use('/watchdog', function (req, res, next) {
  var t = moment.duration(parseInt(req.param('uptime')), 'milliseconds')
  var _message = req.param('ip') + " uptime " + t.hours() + "h " + t.minutes() + "m " + t.seconds() +"s";
  console.log("watchdog from " + _message);
  res.send("You are alive!\n");
});

app.listen(8080);

Here's setup()

void setup() {
  Serial.begin(115200);
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");  
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  
   // Configure the PulseSensor manager.
  pulseSensor.analogInput(PIN_INPUT);
  pulseSensor.blinkOnPulse(PIN_BLINK);
  
  // pulseSensor.fadeOnPulse(PIN_FADE);
  pulseSensor.setSerial(Serial);
  pulseSensor.setOutputType(OUTPUT_TYPE);

  // Skip the first SAMPLES_PER_SERIAL_SAMPLE in the loop().
  samplesUntilReport = SAMPLES_PER_SERIAL_SAMPLE;

  // Now that everything is ready, start reading the PulseSensor signal.
  if (!pulseSensor.begin()) {
    for(;;) {
      // Flash the led to show things didn't work.
      digitalWrite(PIN_BLINK, LOW);
      delay(50);
      digitalWrite(PIN_BLINK, HIGH);
      delay(50);
    }
  }
}

Here's my loop() Thanks in advance!

void loop() {
  unsigned long currentMillis = millis();
  if ( currentMillis - previousMillis > watchdog ) {
    previousMillis = currentMillis;
    WiFiClient client;
  
    if (!client.connect(host, port)) {
      Serial.println("connection failed");
      return;
    }
      
    String url = "/watchdog?command=watchdog&uptime=";
    url += String(millis());
    url += "&ip=";
    url += WiFi.localIP().toString();
    
    // Send the request to the server
    client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" + 
               "Connection: close\r\n\r\n");
    unsigned long timeout = millis();
    while (client.available() == 0) {
      if (millis() - timeout > 5000) {
        Serial.println(">>> Client Timeout !");
        client.stop();
        return;
      }
    }
    // Read all the lines of the reply from server and print them to Serial
    while(client.available()){
      String line = client.readStringUntil('\r');
      Serial.print(line);
    }

  if (pulseSensor.sawNewSample()) {
    if (--samplesUntilReport == (byte) 0) {
      samplesUntilReport = SAMPLES_PER_SERIAL_SAMPLE;     
      pulseSensor.outputSample(); // returns Sensors, SensorCount            
    }
  }
 }
}

You'll continue to have problems until you post ALL of your code AND links to non-standard libraries AND a schematic.

What does this line of code do?

  pulseSensor.setSerial(Serial);

Without a clue as to what pulseSensor is an instance of, and a schematic, we can only guess. I hate guessing games.

Here’s some more info: Thanks very much in advance!

pulse.Sensor.setSerial(Serial) seems to come from

void PulseSensorPlayground::setSerial(Stream &output) {
  SerialOutput.setSerial(output);
}

which is located in PulseSensorPlayrgound.cpp I’m not very good with cpp.
The code works by taking in an analog input on pin A0 and processing it to make it come out as a String via Serial. Look in PulseSensor.h, download master folder from link, look in utility folder. All the PulseSensor libraries are at that link, although I’ve linked to them below again.

Schematic-wise: The Pulse Sensor has 3 pins, 3.3V, GND and Analog. It plugs into the Huzzah board in those 3 places (3.3V, GND, A). The Huzzah board is connected to my laptop via a FTDI cable.

Here is the link to the library PulseSensorPlayground,
and ESP8266WiFi link, and I’m not using the ESP8266HTTPClient.h, but I’ve linked to it.

My code as written above, is nearly complete. here’s the entirety.

/* TCP/IP communication ESP8266WiFi
 * http://www.projetsdiy.fr - https://www.diyprojects.io
 */ 

#define USE_ARDUINO_INTERRUPTS false
#include <PulseSensorPlayground.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
const char* ssid     = "xxxx";            // SSID
const char* password = "xxxx";        // Password
const char* host = "192.168.1.xx";   // IP on my computer
const int   port = 8080;             // server Port
const int   watchdog = 5000;         // watchdog frequency
unsigned long previousMillis = millis(); 

  
const int OUTPUT_TYPE = SERIAL_PLOTTER;
const int PIN_INPUT = 0;    // only one analog input on the HUZZAH
const int PIN_BLINK = 0;    // Pin 0 is the HUZZAH on-board RED LED

byte samplesUntilReport;
const byte SAMPLES_PER_SERIAL_SAMPLE = 10;

PulseSensorPlayground pulseSensor; // all the pulseSensor functions


void setup() {
  Serial.begin(115200);
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");  
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  
   // Configure the PulseSensor manager.
  pulseSensor.analogInput(PIN_INPUT);
  pulseSensor.blinkOnPulse(PIN_BLINK);
  
  // pulseSensor.fadeOnPulse(PIN_FADE);
  pulseSensor.setSerial(Serial);
  pulseSensor.setOutputType(OUTPUT_TYPE);

  // Skip the first SAMPLES_PER_SERIAL_SAMPLE in the loop().
  samplesUntilReport = SAMPLES_PER_SERIAL_SAMPLE;

  // Now that everything is ready, start reading the PulseSensor signal.
  if (!pulseSensor.begin()) {
    for(;;) {
      // Flash the led to show things didn't work.
      digitalWrite(PIN_BLINK, LOW);
      delay(50);
      digitalWrite(PIN_BLINK, HIGH);
      delay(50);
    }
  }
}

void loop() {
  unsigned long currentMillis = millis();
  if ( currentMillis - previousMillis > watchdog ) {
    previousMillis = currentMillis;
    WiFiClient client;
  
    if (!client.connect(host, port)) {
      Serial.println("connection failed");
      return;
    }
      
    String url = "/watchdog?command=watchdog&uptime=";
    url += String(millis());
    url += "&ip=";
    url += WiFi.localIP().toString();
    
    // Send the request to the server
    client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" + 
               "Connection: close\r\n\r\n");
    unsigned long timeout = millis();
    while (client.available() == 0) {
      if (millis() - timeout > 5000) {
        Serial.println(">>> Client Timeout !");
        client.stop();
        return;
      }
    }
    // Read all the lines of the reply from server and print them to Serial
    while(client.available()){
      String line = client.readStringUntil('\r');
      Serial.print(line);
    }

  if (pulseSensor.sawNewSample()) {
    if (--samplesUntilReport == (byte) 0) {
      samplesUntilReport = SAMPLES_PER_SERIAL_SAMPLE;     
      pulseSensor.outputSample(); // returns Sensors, SensorCount            
    }
  }
 }
}

On each pass through loop(), you see if there is a new sample. If there is, and enough of them have been collected, you tell your neighbor to get the latest data, and tell the rest of the neighbors BUT NOT TO TELL YOU.

And, yet you want to tell the world.

Does that make sense? Look at ALL of the methods available in the pulse sensor playground (stupidly long name) class. I'm sure you'll find something useful.

Even once I figure out which methods are creating the values I need,
the issue is that conceptually I don't understand how to link the methods to the server.

Can someone explain this to me?

I get a print out on serial monitor:

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 15
ETag: W/"f-PW7bZwmvSbz169ZBLM+4NynPoGk"
Date: Sat, 01 Jul 2017 15:33:28 GMT
Connection: close

And this on terminal:
watchdog from 192.168.1.39 uptime 0h 1m 53s
watchdog from 192.168.1.39 uptime 0h 1m 58s

Can someone explain this to me?

What don't you understand?

    String url = "/watchdog?command=watchdog&uptime=";
    url += String(millis());
    url += "&ip=";
    url += WiFi.localIP().toString();
    
    // Send the request to the server

Why do you want to know this information? It seems like what you want to know is some, or all of, the pulse sensor data.

When you send data to the server, using a GET request, the server makes a reply. That reply is read using:

    // Read all the lines of the reply from server and print them to Serial
    while(client.available()){
      String line = client.readStringUntil('\r');
      Serial.print(line);
    }

Anonymous printing sucks. When you see data in the Serial Monitor, you haven't a clue what it is, or where it came from.

Change:

      Serial.print(line);

to

      Serial.print("Server response: [");
      Serial.print(line);
      Serial.println("]");

Perhaps what you see on the Serial Monitor will then make more sense.

What does the pulse sensor output look like?

OK “Server response” line is helpful, thanks.

The pulse sensor data looks good.
On scope I see an analog signal between 0 and 1 V (I have voltage divider to scale signal), and if I remove the server code, on serial monitor I see numbers in the low 70s.
For clarity, here’s the code:

#define USE_ARDUINO_INTERRUPTS false
#include <PulseSensorPlayground.h>
const int OUTPUT_TYPE = SERIAL_PLOTTER;

const int PIN_INPUT = 0;    // only one analog input on the HUZZAH
const int PIN_BLINK = 0;    // Pin 0 is the HUZZAH on-board RED LED
//const int PIN_FADE = 5;   // no fade pin... yet

byte samplesUntilReport;
const byte SAMPLES_PER_SERIAL_SAMPLE = 10;

/*
   All the PulseSensor Playground functions.
*/
PulseSensorPlayground pulseSensor;

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

  // Configure the PulseSensor manager.
  pulseSensor.analogInput(PIN_INPUT);
  pulseSensor.blinkOnPulse(PIN_BLINK);
  
  pulseSensor.setSerial(Serial);
  pulseSensor.setOutputType(OUTPUT_TYPE);

  // Skip the first SAMPLES_PER_SERIAL_SAMPLE in the loop().
  samplesUntilReport = SAMPLES_PER_SERIAL_SAMPLE;

  // Now that everything is ready, start reading the PulseSensor signal.
  if (!pulseSensor.begin()) {
    for(;;) {
      // Flash the led to show things didn't work.
      digitalWrite(PIN_BLINK, LOW);
      delay(50);
      digitalWrite(PIN_BLINK, HIGH);
      delay(50);
    }
  }
}

void loop() {
  if (pulseSensor.sawNewSample()) {
    if (--samplesUntilReport == (byte) 0) {
      samplesUntilReport = SAMPLES_PER_SERIAL_SAMPLE;
      pulseSensor.outputSample();

    }


  }

}

With the GET request, I rarely see any numbers coming from the pulse sensor.

I think what I need to do is have the server request the data from the pulse sensor
and print it that way. Does that sound right? Is this a POST request?

I think what I need to do is have the server request the data from the pulse sensor
and print it that way. Does that sound right?

No. Every time there is new data from the sensor, collect the data.

Then, when the watchdog bites, send the newest data from the sensor, by making a GET request.

I'm collecting data from the sensor on A0

  String yes =  String(analogRead(0), DEC);

Adding yes into GET command does not result in printing the data with the watchdog:

client.print(String("GET ") + url + yes +
               " HTTP/1.1\r\n" + 
               "Host: " + host + "\r\n" + 
               "Connection: close\r\n\r\n");

How does the server know what "tag" to look for?
This code using the url is an example, how does the server interpret these variables?
Thanks!

How does the server know what "tag" to look for?

The server doesn't. The server is where some script runs. The script expects name=value pairs, with specific names.

You need to send your data to a different script, unless you modify the script that you are calling to expect an additional name with value AND you supply the name and value correctly.