I am using a project with an MQ138 sensor and want to push the real time sensor reads to firebase. Currently, the wifi/firebase part and sensor part work fine separately. The code connects to wifi and will update a temporary variable (just an int that gets 1 added to it every time the loop runs) and put that on firebase. On a separate arduino file, the code is also able to read the sensor, do math with it, and consistently update. However, when I put the two together and try to print the sensor output, the value does not change at all (both the raw analogRead AND the raw value after being put through some math)--even when it does change on the separate code I ran without any firebase/wifi involved.
Why is this? Could there be some sort of cache that saves the old sensor value? Something with the way the code loops? The only different between the firebase code and the sensor test code (without use of firebase) is that on the Arduino software the board has to be selected as ESP8266 for firebase/wifi connection to work, but the test code uses Arduino Uno as a board. Could there be something with this that is not letting AnalogRead (for the sensor) work properly?
The circuit is wired so that the ESP8266 and MQ138 sensor are both connected to an Arduino Uno.
My code is below (currently, the sensor output is only getting printed in serial, and the integer "n" is consistently getting updated and pushed on firebase, but even the serial output of the sensor won't change):
#include <Firebase.h>
#include <FirebaseArduino.h>
#include <FirebaseCloudMessaging.h>
#include <FirebaseError.h>
#include <FirebaseHttpClient.h>
#include <FirebaseObject.h>
#include <dummy.h>
#include <ESP8266WiFi.h>
#include <FirebaseArduino.h>
#include <SPI.h>
#include <Wire.h>
#include <DHT.h>
#include <Adafruit_BMP085.h>
//passwords have been removed, but are in the actual code
#define FIREBASE_HOST ""
#define FIREBASE_AUTH ""
#define WIFI_SSID ""
#define WIFI_PASSWORD ""
//Hardware Macros for sensor
#define MQ138 (5) //Analog 5 input
#define RL_VALUE (10000) //Load resistance in ohms
//Software macros
#define CALIBRATION_SAMPLE_TIMES (40) //define how many samples you are going to take in the calibration phase
#define CALIBRATION_SAMPLE_INTERVAL (500) //define the time interal(in milisecond) between each samples in the
//cablibration phase
#define READ_SAMPLE_INTERVAL (50) //define how many samples you are going to take in normal operation
#define READ_SAMPLE_TIMES (5) //define the time interal(in milisecond) between each samples in
//Globals for math with the sensor
float AcetoneCurve[2] = {3.720, -2.222}; //A, B
float R0 = 10000; //Initialized to 10k ohms
unsigned long SLEEP_TIME = 600; // Sleep time between reads (in seconds)
int val = 0; // variable to store the value coming from the sensor
float calcVoltage = 0;
float dustDensity = 0;
boolean metric = true;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial.print("help");
WiFi.disconnect();
Serial.setDebugOutput(true);
/*IPAddress ip(192,168,3,34);
IPAddress gateway(192,168,3,1);
IPAddress subnet(255,255,255,0);*/
WiFi.setAutoReconnect(true);
//connect to Wifi
WiFi.mode(WIFI_STA);
WiFi.hostname("ESP-host");
//WiFi.config(ip, gateway, subnet);
WiFi.enableInsecureWEP(true);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("connecting");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
Serial.print("Wifi status: ");
Serial.println(WiFi.status());
delay(500);
}
Serial.println();
Serial.print("connected: ");
Serial.println(WiFi.localIP());
Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
//define pin
pinMode(MQ138, INPUT);
}
int n = 0;
void loop() {
// put your main code here, to run repeatedly:
//MQ138 code
int raw = analogRead(MQ138);
static float Ro = MQCalibration(MQ138, 25, RL_VALUE, AcetoneCurve); //Assuming 25ppm of acetone in clean air?
float Rs = MQRead(MQ138, RL_VALUE);
float ratio = Rs / Ro;
int ppm = MQGetPercentage(ratio, Ro, AcetoneCurve);
//This prints the same output every time, even when it shouldn't
Serial.println(raw);
Serial.print("PPM: ");
Serial.println(ppm);
//Firebase code
// set value
Firebase.setFloat("PPM", n);
//error catching
if (Firebase.failed()) {
Serial.print("setting /number failed:");
Serial.println(Firebase.error());
return;
}
delay(1000);
// appending a new value to /logs, CHANGE INT
String name = Firebase.pushInt("logs", n++);
//handle error
if (Firebase.failed()) {
Serial.print("pushing /logs failed: ");
Serial.println(Firebase.error());
return;
}
Serial.print("pushed: /logs/");
Serial.println(name);
delay(1000);
if (Firebase.failed()) {
return;
}
}
//Functions - for calculating the PPM from a raw sensor reading, can be ignored
/****************** MQResistanceCalculation ****************************************
Input: raw_adc - raw value read from adc, which represents the voltage
Output: the calculated sensor resistance
Remarks: The sensor and the load resistor forms a voltage divider. Given the voltage across the load resistor and its resistance, the resistance of the sensor could be derived.
************************************************************************************/
float MQResistanceCalculation(int raw_adc, float rl_value)
{
return (long)((long)(1024 * 1000 * (long)rl_value) / raw_adc - (long)rl_value);
;
}
/***************************** MQCalibration (R0) ****************************************
Input: mq_pin - analog channel
Output: Ro of the sensor
Remarks: This function assumes that the sensor is in clean air. It use
MQResistanceCalculation to calculates the sensor resistance in clean air. .
************************************************************************************/
float MQCalibration(int mq_pin, double ppm, double rl_value, float *pcurve )
{
int i;
float val = 0;
for (i = 0; i < CALIBRATION_SAMPLE_TIMES; i++) { //take multiple samples
val += MQResistanceCalculation(analogRead(mq_pin), rl_value);
delay(CALIBRATION_SAMPLE_INTERVAL);
}
val = val / CALIBRATION_SAMPLE_TIMES; //calculate the average value
//Ro = Rs * sqrt(a/ppm, b) = Rs * exp( ln(a/ppm) / b )
return (long)val * exp((log(pcurve[0] / ppm) / pcurve[1]));
}
/***************************** MQRead (Rs) *********************************************
Input: mq_pin - analog channel
Output: Rs of the sensor
Remarks: This function use MQResistanceCalculation to caculate the sensor resistenc (Rs).
The Rs changes as the sensor is in the different consentration of the target
gas. The sample times and the time interval between samples could be configured
by changing the definition of the macros.
************************************************************************************/
float MQRead(int mq_pin, float rl_value)
{
int i;
float rs = 0;
for (i = 0; i < READ_SAMPLE_TIMES; i++) {
rs += MQResistanceCalculation(analogRead(mq_pin), rl_value);
delay(READ_SAMPLE_INTERVAL);
}
rs = rs / READ_SAMPLE_TIMES;
return rs;
}
/***************************** MQGetPercentage **********************************
Input: rs_ro_ratio - Rs divided by Ro
pcurve - pointer to the curve of the target gas
Output: ppm of the target gas
Remarks: By using the slope and a point of the line. The x(logarithmic value of ppm)
of the line could be derived if y(rs_ro_ratio) is provided. As it is a
logarithmic coordinate, power of 10 is used to convert the result to non-logarithmic
value.
************************************************************************************/
int MQGetPercentage(float rs_ro_ratio, float ro, float *pcurve)
{
return (double)(pcurve[0] * pow(((double)rs_ro_ratio), pcurve[1]));
}
The code to test the sensor, without integrating firebase and ESP8266, is as follows:
//Source: https://github.com/empierre/arduino-mysensors-contribs/blob/master/AirQuality-Multiple_Gas_Sensor1_4.ino
// Libraries
#include <SPI.h>
#include <Wire.h>
#include <DHT.h>
#include <Adafruit_BMP085.h>
//Hardware Macros
#define MQ138 (5) //Analog 5 input
#define RL_VALUE (10000) //Load resistance in ohms
//Software macros
#define CALIBRATION_SAMPLE_TIMES (40) //define how many samples you are going to take in the calibration phase
#define CALIBRATION_SAMPLE_INTERVAL (500) //define the time interal(in milisecond) between each samples in the
//cablibration phase
#define READ_SAMPLE_INTERVAL (50) //define how many samples you are going to take in normal operation
#define READ_SAMPLE_TIMES (5) //define the time interal(in milisecond) between each samples in
//Globals
float AcetoneCurve[2] = {3.720, -2.222}; //A, B
float R0 = 10000; //Initialized to 10k ohms
unsigned long SLEEP_TIME = 600; // Sleep time between reads (in seconds)
int val = 0; // variable to store the value coming from the sensor
//idfk what this is
float calcVoltage = 0;
float dustDensity = 0;
boolean metric = true;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(MQ138, INPUT);
}
void loop() {
// put your main code here, to run repeatedly:
int raw = analogRead(MQ138);
static float Ro = MQCalibration(MQ138, 25, RL_VALUE, AcetoneCurve); //Assuming 25ppm of acetone in clean air?
//https://www.health.ny.gov/environmental/indoors/air/contaminants/acetone.htm#:~:text=Levels%20of%20acetone%20are%20typically,common%20ingredient%20in%20many%20products.
float Rs = MQRead(MQ138, RL_VALUE);
float ratio = Rs / Ro;
int ppm = MQGetPercentage(ratio, Ro, AcetoneCurve);
Serial.println(raw);
Serial.print("PPM: ");
Serial.println(ppm);
}
//Functions
/****************** MQResistanceCalculation ****************************************
Input: raw_adc - raw value read from adc, which represents the voltage
Output: the calculated sensor resistance
Remarks: The sensor and the load resistor forms a voltage divider. Given the voltage across the load resistor and its resistance, the resistance of the sensor could be derived.
************************************************************************************/
float MQResistanceCalculation(int raw_adc,float rl_value)
{
return (long)((long)(1024*1000*(long)rl_value)/raw_adc-(long)rl_value);
;
}
/***************************** MQCalibration (R0) ****************************************
Input: mq_pin - analog channel
Output: Ro of the sensor
Remarks: This function assumes that the sensor is in clean air. It use
MQResistanceCalculation to calculates the sensor resistance in clean air. .
************************************************************************************/
float MQCalibration(int mq_pin, double ppm, double rl_value,float *pcurve )
{
int i;
float val=0;
for (i=0;i<CALIBRATION_SAMPLE_TIMES;i++) { //take multiple samples
val += MQResistanceCalculation(analogRead(mq_pin),rl_value);
delay(CALIBRATION_SAMPLE_INTERVAL);
}
val = val/CALIBRATION_SAMPLE_TIMES; //calculate the average value
//Ro = Rs * sqrt(a/ppm, b) = Rs * exp( ln(a/ppm) / b )
return (long)val*exp((log(pcurve[0]/ppm)/pcurve[1]));
}
/***************************** MQRead (Rs) *********************************************
Input: mq_pin - analog channel
Output: Rs of the sensor
Remarks: This function use MQResistanceCalculation to caculate the sensor resistenc (Rs).
The Rs changes as the sensor is in the different consentration of the target
gas. The sample times and the time interval between samples could be configured
by changing the definition of the macros.
************************************************************************************/
float MQRead(int mq_pin,float rl_value)
{
int i;
float rs=0;
for (i=0;i<READ_SAMPLE_TIMES;i++) {
rs += MQResistanceCalculation(analogRead(mq_pin),rl_value);
delay(READ_SAMPLE_INTERVAL);
}
rs = rs/READ_SAMPLE_TIMES;
return rs;
}
/***************************** MQGetPercentage **********************************
Input: rs_ro_ratio - Rs divided by Ro
pcurve - pointer to the curve of the target gas
Output: ppm of the target gas
Remarks: By using the slope and a point of the line. The x(logarithmic value of ppm)
of the line could be derived if y(rs_ro_ratio) is provided. As it is a
logarithmic coordinate, power of 10 is used to convert the result to non-logarithmic
value.
************************************************************************************/
int MQGetPercentage(float rs_ro_ratio, float ro, float *pcurve)
{
return (double)(pcurve[0] * pow(((double)rs_ro_ratio), pcurve[1]));
}
Any help would be much appreciated!