NodeMCU with 2 sensors reading sent to the Cloud (ThingSpeak)

Dear all,

I am trying to read some data from 2 sensors (T/RH with DHT22, Oxygen % with ME3-O2) through NodeMCU and send them to ThingSpeak on the Cloud.

I wrote a succesful code (thanks to great users help) in this other thread (Just for reference).

I am trying to read from the only analog input I have on the NodeMCU and send it to the Cloud.

Here is the code:

// IoT project for T/RH (DHT22) and Oxygen content (ME3-O2) with NodeMCU

// Libraries
#include <DHT.h> // Lib for the T/RH sensor
#include <ESP8266WiFi.h> // Lib for the Wi-Fi
#include <WiFiClient.h> // Lib for the Wi-Fi
#include <ThingSpeak.h> // Lib for the cloud https://thingspeak.com/

// // Define the DHT22 sensor variables:
#define DHTPIN D5 // Signal pin for the DHT22 sensor
#define DHTTYPE DHT22 // Define the type of sensor
DHT dht(DHTPIN, DHTTYPE); // Create a DHT object
uint8_t t, h; // Temperature and relative humidity variables

// Define the ME3-O2 sensor variables:
float sensorValue = analogRead(A0); // Read the sensor data from the analog pin
float sensorVoltage = (sensorValue / 1024) * 5.0; // Adapt the output with a fraction of 0-5V input from Arduino Voltage. In V.
float SensorVoltageADJ = sensorVoltage / 344 * 1000; // I am getting rid of the OPAmp. We can use this in the characteristic curve provided with the sensor. In mV.
float oxyCont = SensorVoltageADJ * 20.95 / 5.90; // Calibration with reference to standard condition (linear interpolation)

// Define the Wi-Fi and Cloud variables:
const char* ssid = "MyNetwork"; // The SSID (name) of the Wi-Fi network you want to connect to
const char* password = "MyPassword"; // The password of the Wi-Fi network
WiFiClient client; // Create a client that can connect to a specified internet IP address and port
unsigned long myChannelNumber = MyChannelNumber; // ThingSpeak channel number
const char * myWriteAPIKey = "MYAPIkey"; // ThingSpeak API write key

//============================================

void setup()
{
  Serial.begin(115200); // Start the Serial communication to send messages to the computer
  delay(10);
  // Connect to Wi-Fi network
  Serial.println('\n');
  WiFi.begin(ssid, password); // Connect to the network
  Serial.print("Connecting to ");
  Serial.print(ssid);
  Serial.println(" ...");
  int i = 0;
  while (WiFi.status() != WL_CONNECTED) // Wait for the Wi-Fi to connect
  {
    delay(1000);
    Serial.print(++i); Serial.print(' ');
  }
  Serial.println('\n');
  Serial.println("Connection established!");
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP()); // Send the IP address of the ESP8266 to the computer
  Serial.println('\n');
  ThingSpeak.begin(client); // Connect to the Cloud (
}

//============================================

void loop()
{
  static boolean data_state = false;
  t = dht.readTemperature(); // Get the values of the temperature
  h = dht.readHumidity(); // Get the values of the relative humidity
  Serial.print("Temperature:");
  Serial.print(t);
  Serial.println("C");
  Serial.print("Relative Humidity:");
  Serial.print(h);
  Serial.println("%");
  Serial.println('\n');
  Serial.print(oxyCont);
  Serial.println("%");
  Serial.println('\n');
  // Write to ThingSpeak. There are up to 8 fields in a channel, allowing you to store up to 8 different
  // pieces of information in a channel. Here, we write to field 1 and then 2.
  if ( data_state )
  {
    ThingSpeak.writeField(myChannelNumber, 1, t, myWriteAPIKey); // Send Temperature to the Cloud
    data_state = false;
  }
  else
  {
    ThingSpeak.writeField(myChannelNumber, 2, h, myWriteAPIKey); // Send Relative Humidity to the Cloud
    data_state = true;
  }

  ThingSpeak.writeField(myChannelNumber, 3, oxyCont, myWriteAPIKey); // Send Temperature to the Cloud

  delay(30000); // IMPORTANT - ThingSpeak will only accept updates every 15 seconds (FREE LICENCE)
}

I have got few questions for the community, please:

  1. The code is now compiling, but perhaps may kindly someone troubleshoot it or give me a warning if you notice something that is not-appropriate please?

  2. May I get the values of T/RH with some decimal digits using "float" instead of uint8_t?

  3. In the loop I am trying to write on channel field 1, then IF it is written, I will write in channel field 2 and then IF it is written in 1 and 2 I will write in 3. then start from the beginning. I mean, I would like to be sure that before writing in a field, I already wrote the data in the previous one.
    Is this a good idea or I could just put something like:

ThingSpeak.writeField(myChannelNumber, 1, t, myWriteAPIKey); // Send Temperature to the Cloud
ThingSpeak.writeField(myChannelNumber, 2, h, myWriteAPIKey); // Send Relative Humidity to the Cloud
ThingSpeak.writeField(myChannelNumber, 3, oxyCont, myWriteAPIKey); // Send O2% to the Cloud

if is not too efficient (or may create issues long term...) I can I implement that condition of writing in a channel only if the available information related to the previous field have been written in the previous field?

I appreciate there are lot of questions but I am working on this for few hours and I put them alltogether now :slight_smile:

Thanks a lot guys.

M.

float sensorValue = analogRead(A0); // Read the sensor data from the analog pin

It's silly to read this pin before the hardware is ready.

All values that depend on the poorly-named sensorValue are meaningless, because sensorValue does not contain meaningful data.

  1. May I get the values of T/RH with some decimal digits using "float" instead of uint8_t?

If the appropriate methods return floats, yes.

  1. In the loop I am trying to write on channel field 1, then IF it is written, I will write in channel field 2 and then IF it is written in 1 and 2 I will write in 3. then start from the beginning. I mean, I would like to be sure that before writing in a field, I already wrote the data in the previous one.

That may be what you want, but that is not what you are doing.

or I could just put something like:

That makes more sense to me.

It looks like you are reading the ME3-02 sensor only once, not in the loop().
This statement may not be appropriate for an ESP8266 where the reference voltage is 1 volt:

float sensorVoltage = (sensorValue / 1024) * 5.0; // Adapt the output with a fraction of 0-5V input from Arduino Voltage. In V.

Are you trying to ensure that no data is written to ThingSpeak unless all 3 sensors are delivering plausible results ?

Thanks guys for the first insights and suggestions.

I did not want to become silly :slight_smile:

I will come back as soon as I make some adjustment.

PaulS:

float sensorValue = analogRead(A0); // Read the sensor data from the analog pin

It's silly to read this pin before the hardware is ready.

Sorry Paul, I did not understand this statement. How can I make the hardware "ready"? Usually I just send an instruction to read from the sensor and write it somewhere...may you kindly widen a bit your answer please?

[/quote]

PaulS:
All values that depend on the poorly-named sensorValue are meaningless, because sensorValue does not contain meaningful data.

I put better names,
I definied Temperature and RH as float number now,
I also deleted the "IF...ELSE" statements. I just wanted to be sure that after the code fill up the field, the previous field had received data properly, but perhaps is not necessary...in a tutorial I found this bit of code with a "flag" for the "state", but I am having difficult to adapt to 3 (or more) fields at the moment. If necessary (Is it? please advise here), please do not help at this stage, I would like to try myself to code the IF-ELSE statement. Thanks.

Tutorial code:

void loop()
{
  static boolean data_state = false;
  t = dht.readTemperature(); // Get the values of the temperature
  h = dht.readHumidity(); // Get the values of the relative humidity
  Serial.print("Temperature:");
  Serial.print(t);
  Serial.println("C");
  Serial.print("Relative Humidity:");
  Serial.print(h);
  Serial.println("%");
  Serial.println('\n');
  // Write to ThingSpeak. There are up to 8 fields in a channel, allowing you to store up to 8 different
  // pieces of information in a channel. Here, we write to field 1 and then 2.
  if ( data_state )
  {
    ThingSpeak.writeField(myChannelNumber, 1, t, myWriteAPIKey); // Send Temperature to the Cloud
    data_state = false;
  }
  else
  {
    ThingSpeak.writeField(myChannelNumber, 2, h, myWriteAPIKey); // Send Relative Humidity to the Cloud
    data_state = true;

6v6gt:
It looks like you are reading the ME3-02 sensor only once, not in the loop().
This statement may not be appropriate for an ESP8266 where the reference voltage is 1 volt:

float sensorVoltage = (sensorValue / 1024) * 5.0; // Adapt the output with a fraction of 0-5V input from Arduino Voltage. In V.

Are you trying to ensure that no data is written to ThingSpeak unless all 3 sensors are delivering plausible results ?

I changed the 5V to 1V (I had still in my head the Arduino board sorry, silly mistake)
I also put the reading of the oxygen sensor in the loop.

I did not put that check you are talking about. I was just referencing to the quoted bit of tutorial code above where the guy used a IF-ELSE statement to be sure that the 2nd field has been filled once the first it was filled I believe. Perhaps a redundant check?

Thanks a lot Paul and 6v6gt :slight_smile:


New code:

// IoT project for T/RH (DHT22) and Oxygen content (ME3-O2) with NodeMCU

// Libraries
#include <DHT.h> // Lib for the T/RH sensor
#include <ESP8266WiFi.h> // Lib for the Wi-Fi
#include <WiFiClient.h> // Lib for the Wi-Fi
#include <ThingSpeak.h> // Lib for the cloud https://thingspeak.com/

// // Define the DHT22 sensor variables:
#define DHTPIN D5 // Signal pin for the DHT22 sensor
#define DHTTYPE DHT22 // Define the type of sensor
DHT dht(DHTPIN, DHTTYPE); // Create a DHT object
// uint8_t t, h; // Temperature and relative humidity variables
float t, h; // Temperature and relative humidity variables

// Define the ME3-O2 sensor variables:
float O2raw;
float O2V = (O2raw / 1024) * 1.0; // Adapt the output with a fraction of 0-1V input from NodeMCU Voltage. In V.
float O2Vadj = O2V / 344 * 1000; // I am getting rid of the OPAmp. We can use this in the characteristic curve provided with the sensor. In mV.
float O2content = O2Vadj * 20.95 / 5.90; // Calibration with reference to standard condition (linear interpolation)

// Define the Wi-Fi and Cloud variables:
const char* ssid = "Mynetwork"; // The SSID (name) of the Wi-Fi network you want to connect to
const char* password = "Mypassw"; // The password of the Wi-Fi network
WiFiClient client; // Create a client that can connect to a specified internet IP address and port
unsigned long myChannelNumber = Mychannel; // ThingSpeak channel number
const char * myWriteAPIKey = "Mykey"; // ThingSpeak API write key

//============================================

void setup()
{
  Serial.begin(115200); // Start the Serial communication to send messages to the computer
  delay(10);
  // Connect to Wi-Fi network
  Serial.println('\n');
  WiFi.begin(ssid, password); // Connect to the network
  Serial.print("Connecting to ");
  Serial.print(ssid);
  Serial.println(" ...");
  int i = 0;
  while (WiFi.status() != WL_CONNECTED) // Wait for the Wi-Fi to connect
  {
    delay(1000);
    Serial.print(++i); Serial.print(' ');
  }
  Serial.println('\n');
  Serial.println("Connection established!");
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP()); // Send the IP address of the ESP8266 to the computer
  Serial.println('\n');
  ThingSpeak.begin(client); // Connect to the Cloud (
}

//============================================

void loop()
{
  t = dht.readTemperature(); // Get the values of the temperature
  h = dht.readHumidity(); // Get the values of the relative humidity
  O2raw = analogRead(A0); // Read the Oxygen sensor data from the analog pin
  Serial.print("Temperature:");
  Serial.print(t);
  Serial.println("C");
  Serial.print("Relative Humidity:");
  Serial.print(h);
  Serial.println("%");
  Serial.println('\n');
  Serial.print(O2content);
  Serial.println("%");
  Serial.println('\n');
  // Write to ThingSpeak
  ThingSpeak.writeField(myChannelNumber, 1, t, myWriteAPIKey); // Send Temperature to the Cloud
  ThingSpeak.writeField(myChannelNumber, 2, h, myWriteAPIKey); // Send Relative Humidity to the Cloud
  ThingSpeak.writeField(myChannelNumber, 3, O2content, myWriteAPIKey); // Send O2% to the Cloud
  delay(30000); // IMPORTANT - ThingSpeak will only accept updates every 15 seconds (FREE LICENCE)
}

How can I make the hardware "ready"?

The IDE handles that for you. Once the global variables are initialized, the init() method is called to get the hardware ready to use. Then, setup() is called. Finally, loop() is called in an infinite loop.

Usually I just send an instruction to read from the sensor and write it somewhere...may you kindly widen a bit your answer please?

That's the proper thing to do, IF you read from and/or write to the sensor in a reasonable place in the code (in setup() if you want to do it once; in loop() if you want to do it over and over).

in a tutorial I found this bit of code with a "flag" for the "state", but I am having difficult to adapt to 3 (or more) fields at the moment.

A flag (boolean) has two values - true or false. You need some other mechanism to deal with three or more states, such as a byte.

Of course, you don't really have three states. You have three values before you write anything to thinksqueak, so just write them all at once.

If necessary (Is it?

It is only necessary if you wish to avoid writing NAN to thingsqueak, while still writing the other one or two values. Personally, I'd just replace NAN with -99, and write a value every time. I know that it never gets to -99 degrees or -99 % RH, so I can tell that -99 means that a sensor was being senseless.

Dear Paul,

Really thanks for that. I will have a closer look, study a bit more of missing stuff and adapt the code again for your consideration (and others).

Just a quick question to whoever could answer...

IF I want to power my NodeMCU connected to T/RH sensor (and the O2 sensor as well) through a simple wall plug...will I have any issue?
I have a Samsung smartphone charger. I used its cable to upload the code to the NodeMCU (the connection is the same as the one of the Samsung smartphone...) and also to power it throught the computer USB port...
If I now use the charger connected to the wall to power the NodeMCU???

It might be silly, but hope not.

Thanks.

IF I want to power my NodeMCU connected to T/RH sensor (and the O2 sensor as well) through a simple wall plug...will I have any issue?

If you use a "wall plug" that provides the proper voltage and sufficient current, no.

Samsung charger has an output of 5V/2A
I suppose it is going to be fine for my NodeMCU right? :sunglasses:

I suppose it is going to be fine for my NodeMCU right?

You'll be sure to let us know, right?

Sorry Paul, did you mean that you do not know and I will give my feedback to the community or are you saying that you know the answer already that I will not burn any premises here (my boss will kill me lol) :slight_smile: :slight_smile: :slight_smile:

The voltage that device puts out is correct. The amperage should be sufficient. The only way to know, for sure, is to test it.

my boss will kill me lol

For testing a premise? Even if you try the board (extremely unlikely), he or she is out what? $20?

it was a joke obviously :slight_smile:

In my opinion should be Ok too, I will let you know :slight_smile:

I finally tried the following code for reading the O2 sensor (the readings for T/RH are of course "nan" because I disconnected the DHT22 sensor at the moment)

May please someone troubleshoot my code?

// IoT project for T/RH (DHT22) and Oxygen content (ME3-O2) with NodeMCU

// Libraries
#include <DHT.h> // Lib for the T/RH sensor
#include <ESP8266WiFi.h> // Lib for the Wi-Fi
#include <WiFiClient.h> // Lib for the Wi-Fi
#include <ThingSpeak.h> // Lib for the cloud https://thingspeak.com/

// // Define the DHT22 sensor variables:
#define DHTPIN D5 // Signal pin for the DHT22 sensor
#define DHTTYPE DHT22 // Define the type of sensor
DHT dht(DHTPIN, DHTTYPE); // Create a DHT object
// uint8_t t, h; // Temperature and relative humidity variables
float t, h; // Temperature and relative humidity variables

// Define the ME3-O2 sensor variables:
float O2raw;

// Define the Wi-Fi and Cloud variables:
const char* ssid = "MyNetwork"; // The SSID (name) of the Wi-Fi network you want to connect to
const char* password = "MyPassword"; // The password of the Wi-Fi network
WiFiClient client; // Create a client that can connect to a specified internet IP address and port
unsigned long myChannelNumber = MyChannel; // ThingSpeak channel number
const char * myWriteAPIKey = "MyKey"; // ThingSpeak API write key

//============================================

void setup()
{
  Serial.begin(115200); // Start the Serial communication to send messages to the computer
  delay(10);

  // Connect to Wi-Fi network
  Serial.println('\n');
  WiFi.begin(ssid, password); // Connect to the network
  Serial.print("Connecting to ");
  Serial.print(ssid);
  Serial.println(" ...");
  int i = 0;
  while (WiFi.status() != WL_CONNECTED) // Wait for the Wi-Fi to connect
  {
    delay(1000);
    Serial.print(++i); Serial.print(' ');
  }
  Serial.println('\n');
  Serial.println("Connection established!");
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP()); // Send the IP address of the ESP8266 to the computer
  Serial.println('\n');
  ThingSpeak.begin(client); // Connect to the Cloud through ThingSpeak
}

//============================================

void loop()
{
  // Get the values of temperature, relative humidity and Oxygen
  t = dht.readTemperature();
  h = dht.readHumidity();
  O2raw = analogRead(A0);
  float O2V = (O2raw / 1024); // Adapt the output with a fraction of 0-1V input from NodeMCU Voltage. In V.
  float O2Vadj = O2V / 344 * 1000; // I am getting rid of the OPAmp. We can use this in the characteristic curve provided with the sensor. In mV.
  float O2content = O2Vadj * 20.95 / 1.64; // Calibration with reference to standard condition (linear interpolation)

  // Write to Serial Monitor
  Serial.print("Temperature:");
  Serial.print(t);
  Serial.println("C");
  Serial.print("Relative Humidity:");
  Serial.print(h);
  Serial.println("%");
  Serial.println('\n');
  Serial.print(O2content);
  Serial.println("%");
  Serial.println('\n');

  // Write to ThingSpeak
  ThingSpeak.writeField(myChannelNumber, 1, t, myWriteAPIKey); // Send Temperature to the Cloud
  ThingSpeak.writeField(myChannelNumber, 2, h, myWriteAPIKey); // Send Relative Humidity to the Cloud
  ThingSpeak.writeField(myChannelNumber, 3, O2content, myWriteAPIKey); // Send O2% to the Cloud
  delay(30000); // IMPORTANT - ThingSpeak will only accept updates every 15 seconds (FREE LICENCE)
}

Also please have a look if I "calibrated" the sensor values properly (I am taking as a reference the normal environment condition where we know the O2 content) (O2raw is around 570..):

  O2raw = analogRead(A0);
  float O2V = (O2raw / 1024); // Adapt the output with a fraction of 0-1V input from NodeMCU Voltage. In V.
  float O2Vadj = O2V / 344 * 1000; // I am getting rid of the OPAmp. We can use this in the characteristic curve provided with the sensor. In mV.
  float O2content = O2Vadj * 20.95 / 1.64; // Calibration with reference to standard condition (linear interpolation)

Thanks a lot for this :slight_smile:

NOW:

  1. When I connect the system to the PC (miniUSB cable from a Samsung S6 charger) I can see the following values on the Serial Monitor in the IDE:


(I blew on the sensor)

BUT nothing has been sent/visualised on my ThingSpeak channel...

  1. If I connect the system on a wall plug (as it should be in the future...!) I cannot see anything (of course!) on SM, but nothing has been sent to ThingSpeak to my Channel either :frowning:

Any suggestion please?

May please someone troubleshoot my code?

Nope. You have FAR too much code for reading an O2 sensor.

Write a sketch that does nothing more than read the sensor and print the results.

If that works, the problem is in how that functionality is embedded in the large(r) program. If not, then you have far less code to tweak to get useful data.

If you need help, you'll need to fix your link. "O2 sensor" goes to a porn site.

PaulS:
If you need help, you'll need to fix your link. "O2 sensor" goes to a porn site.

Where is it?? Sorry I cannot see it :frowning: :frowning: :frowning:

// IoT project for Oxygen content (ME3-O2) with NodeMCU

// Libraries
#include <ESP8266WiFi.h> // Lib for the Wi-Fi
#include <WiFiClient.h> // Lib for the Wi-Fi
#include <ThingSpeak.h> // Lib for the cloud https://thingspeak.com/

// Define the ME3-O2 sensor variables:
float O2raw;

// Define the Wi-Fi and Cloud variables:
const char* ssid = "MyNetwork"; // The SSID (name) of the Wi-Fi network you want to connect to
const char* password = "MyPassword"; // The password of the Wi-Fi network
WiFiClient client; // Create a client that can connect to a specified internet IP address and port
unsigned long myChannelNumber = MyChannel; // ThingSpeak channel number
const char * myWriteAPIKey = "MyKey"; // ThingSpeak API write key

//============================================

void setup()
{
  Serial.begin(115200); // Start the Serial communication to send messages to the computer
  delay(10);

  // Connect to Wi-Fi network
  Serial.println('\n');
  WiFi.begin(ssid, password); // Connect to the network
  Serial.print("Connecting to ");
  Serial.print(ssid);
  Serial.println(" ...");
  int i = 0;
  while (WiFi.status() != WL_CONNECTED) // Wait for the Wi-Fi to connect
  {
    delay(1000);
    Serial.print(++i); Serial.print(' ');
  }
  Serial.println('\n');
  Serial.println("Connection established!");
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP()); // Send the IP address of the ESP8266 to the computer
  Serial.println('\n');
  ThingSpeak.begin(client); // Connect to the Cloud through ThingSpeak
}

//============================================

void loop()
{
  O2raw = analogRead(A0); // Get the values of Oxygen
  float O2V = (O2raw / 1024); // Adapt the output with a fraction of 0-1V input from NodeMCU Voltage. In V.
  float O2Vadj = O2V / 344 * 1000; // I am getting rid of the OPAmp. We can use this in the characteristic curve provided with the sensor. In mV.
  float O2content = O2Vadj * 20.95 / 1.64; // Calibration with reference to standard condition (linear interpolation)

  // Write to Serial Monitor
  Serial.print(O2content);
  Serial.println("%");
  Serial.println('\n');

  ThingSpeak.writeField(myChannelNumber, 3, O2content, myWriteAPIKey); // Send O2% to the Cloud
  delay(30000); // IMPORTANT - ThingSpeak will only accept updates every 15 seconds (FREE LICENCE)
}

I made it shorter. is it enough like this Paul?

is it enough like this Paul?

No. You still have way too much code. Reading the sensor and printing to the serial port does NOT require the ESP8266WiFi.h, WiFiClient.h, or ThingSpeak.h header files.

PaulS:
No. You still have way too much code. Reading the sensor and printing to the serial port does NOT require the ESP8266WiFi.h, WiFiClient.h, or ThingSpeak.h header files.

I can read the sensor. If I print the O2raw (the raw readings) I have a value.. Issue is that nothing has been sent to ThingSpeak.

However, now that I got rid of the T/RH fields for ThingSpeak, the senbsor is sending values to the Cloud.

I am wondering if this issue has been related with the fact that I was sending "nan" values to ThingSpeak or for some sort of "timing" issue?

In the meanwhile I will reduce the code further (but, as said the issue is to see the readings on the Cloud....) because - appreciating your help- I like to follow your indications.

Thanks a lot.

P.S. Where is the link to the porn site? :frowning:

P.S. Where is the link to the porn site?

Non-existent. You didn't provide a link to the sensor that you said you were having problems reading.