Chat freely about anything...

User avatar
By cbrum11
#64839 Hello,

I have a Wemos hooked up to a CO2 sensor reading values over I2C.

The CO2 sensor is powered by a separate 12V power supply. I have experimented with powering the Wemos through the serial port attached to a computer and through multiple different cell phone wall plugs.

No matter what I try, the ESP runs the code flawlessly between 3 to 6 times and then only reports 0. Because it only reads 0, the code just loops constantly through trying to get a better/accurate reading. I really don't know if this is a hardware or code issue.

If someone would be kind enough to review the code or offer any suggestions about how to troubleshoot this, it would be greatly appreciated. I'm not sure if the ESP is resetting, running out of RAM, or if its'a completely unrelated problem. I guess I'm asking if there's any known problems with the ESP internally resetting and not continuing to run code. It doesn't appear to turn off though... I'm really at a loss.

Thanks in advance,
Chase

Code: Select all#include <Wire.h>
#include <ESP8266WiFi.h>         //enable ESP8266 Wifi Library
#include <PubSubClient.h>        //enable MQTT Library

/////////////////////////////////////////////
/////// Wifi Variables //////////////////////
/////////////////////////////////////////////
const char* ssid = "greauxeng";        //Internet Network Name
const char* password = "thankful4242";    //Wifi Password
const char* mqtt_server = "192.168.0.1";    //MQTT Server IP Address
WiFiClient espClient;           //Create Wifi client named espClient
char c[8];
/////////////////////////////////////////////
// MQTT Variables ///////////////////////////
/////////////////////////////////////////////
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
/////////////////////////////////////////////
// CO2 VARIABLES ////////////////////////////
/////////////////////////////////////////////
float min_diff = 50;
int CO2min = 200;       //Below which CO2 is considered LOW
int CO2max = 800;       //Above which CO2 is considered HIGH
int SolenoidPin = D8;
int SensorPin = D7;
int BuzzerPin = D5;
long previousMillis = 0;
long interval = 7000; //time to keep solenoid open

int diff1;    //Stores the difference between sequential readings
int diff2;
int diff3;

int CO2_1;    //Stores each CO2 reading
int CO2_2;
int CO2_3;


/////////////////////////////////////////////
// Wifi-Setup Function //////////////////////
/////////////////////////////////////////////

void setup_wifi() {

  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.persistent(false); //These 3 lines are a required work around
  WiFi.mode(WIFI_OFF);    //otherwise the module will not reconnect
  WiFi.mode(WIFI_STA);    //if it gets disconnected
  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());
}

///////////////////////////////////////////////
// Callback Function //////////////////////////
///////////////////////////////////////////////

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

///////////////////////////////////////////////
// Reconnect Function /////////////////////////
///////////////////////////////////////////////

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("ESP8266Client")) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("outTopic", "hello world");
      // ... and resubscribe
      client.subscribe("inTopic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

//////////////////////////////////
//////////////////////////////////
// Read CO2 over I2C Function ////
//////////////////////////////////
//////////////////////////////////

int readCO2()
{
  int co2Addr = 0x68; //address of CO2 sensor
  int co2_value = 0;  //CO2 value stored inside this variable.

  //////////////////////////
  /* Begin Write Sequence */
  //////////////////////////

  Wire.beginTransmission(co2Addr);
  Wire.write(0x22);
  Wire.write(0x00);
  Wire.write(0x08);
  Wire.write(0x2A);

  Wire.endTransmission();

  /////////////////////////
  /* End Write Sequence. */
  /////////////////////////

  /*
    We wait 10ms for the sensor to process our command.
    The sensors's primary duties are to accurately
    measure CO2 values. Waiting 10ms will ensure the
    data is properly written to RAM

  */

  delay(100);

  /////////////////////////
  /* Begin Read Sequence */
  /////////////////////////

  /*
    Since we requested 2 bytes from the sensor we must
    read in 4 bytes. This includes the payload, checksum,
    and command status byte.

  */

  Wire.requestFrom(co2Addr, 4);

  byte i = 0;
  byte buffer[4] = {0, 0, 0, 0};

  /*
    Wire.available() is not nessessary. Implementation is obscure but we leave
    it in here for portability and to future proof our code
  */
  while (Wire.available())
  {
    buffer[i] = Wire.read();
    i++;
  }

  ///////////////////////
  /* End Read Sequence */
  ///////////////////////

  /*
    Using some bitwise manipulation we will shift our buffer
    into an integer for general consumption
  */

  co2_value = 0;
  co2_value |= buffer[1] & 0xFF;
  co2_value = co2_value << 8;
  co2_value |= buffer[2] & 0xFF;

  byte sum = 0; //Checksum Byte
  sum = buffer[0] + buffer[1] + buffer[2]; //Byte addition utilizes overflow

  if (sum == buffer[3])
  {
    return co2_value;
  }
  else
  {
    // Failure!
    /*
      Checksum failure can be due to a number of factors,
      fuzzy electrons, sensor busy, etc.
    */
    return 0;
  }
}


void setup()
{

  Serial.begin(9600);
  Serial.println("The Greaux Engineering CO2 System is Active...");
  pinMode(BuzzerPin, OUTPUT);
  digitalWrite(BuzzerPin, LOW);
  pinMode(SolenoidPin, OUTPUT);
  digitalWrite(SolenoidPin, LOW);
  Wire.begin();
  delay(1000);
  Serial.println("Initializing the Sensor...");
  pinMode (SensorPin, OUTPUT);
  digitalWrite(SensorPin, LOW);
  delay(2000);
  digitalWrite(SensorPin, HIGH);
  Serial.println("Sensor Initialized");
  delay(1000);
  setup_wifi();                         //run wifi setup function
  client.setServer(mqtt_server, 1883);  //Set MQTT server to port 1883
  client.setCallback(callback);         //Setup callback function

}

void loop()
{
  ////////////////////////////////////////
  // Handeling Wifi disconnect ///////////
  ////////////////////////////////////////

  if (!client.connected()) {
    reconnect();
  }
  client.loop();
  Serial.println("Measuring CO2:...");

  /////////////////////////////////////////
  //Trying to achieve an accurate CO2 Reading
  ////////////////////////////////////////

  CO2_1 = readCO2();
  Serial.println(CO2_1);
  delay(4000);
  CO2_2 = readCO2();
  Serial.println(CO2_2);
  delay(4000);
  CO2_3 = readCO2();
  Serial.println(CO2_3);
  delay(4000);

  if ((CO2_1 == 0) || (CO2_2 == 0) || (CO2_3 == 0))
  {
    Serial.println("Publish message: CO2 Value is Reading 0: SENSOR MALFUNCTION");
    client.publish("sensor/co2/status", "SENSOR MALFUNCTION");
    client.publish("sensor/co2/value", "0");
  }
  else {

    diff1 = CO2_1 - CO2_2;
    diff2 = CO2_2 - CO2_3;
    diff3 = CO2_3 - CO2_1;

    //////////////////////////////////////////
    //If the difference between three readings
    //is less than what we set, we can assume
    //reading is accurate.  If not we skip back up
    //and take 3 more readings
    //////////////////////////////////////////

    Serial.println("The differences between values are");
    Serial.println(fabs(diff1));
    delay(500);
    Serial.println(fabs(diff2));
    delay(500);
    Serial.println(fabs(diff3));
    delay(500);

    if ((fabs(diff1) <= min_diff) && (fabs(diff2) <= min_diff) && (fabs(diff3) <= min_diff))
    {


      Serial.println("CO2 Reading is ACCURATE...");
      client.publish("sensor/co2/status", "CO2 Reading is ACCURATE...");

      ///////////////////////////////////////////////////////
      //Once we have an accurate reading, if the
      //CO2 level is outside our acceptable range
      //we open the solenoid for a specified amount of time
      //The millis stuff keeps looping the code until
      //we reach our set time interval
      /////////////////////////////////////////////////////

      if (CO2_3 <= CO2min) {
        Serial.print("Publish message: CO2 Reading is LOW: ");
        Serial.println(CO2_3);
        Serial.println("RELEASING CO2");
        client.publish("sensor/co2/status","LOW.");
        snprintf(msg, 75, "%ld", CO2_3);
        client.publish("sensor/co2/value", msg);
        client.publish("sensor/co2/status","RELEASING CO2");

        unsigned long currentMillis = millis();
        Serial.println(currentMillis);
        while (abs(currentMillis - millis()) < interval)
        {
          digitalWrite(SolenoidPin, HIGH);
        }
        delay(7000);
        Serial.println(millis());
        digitalWrite(SolenoidPin, LOW);
        client.publish("sensor/co2/status", "END RELEASE CO2");
      }


      else if ((CO2_3 > CO2min) && (CO2_3 < CO2max)) {
        Serial.println("CO2 is IN RANGE");
        Serial.println(CO2_3);
        client.publish("sensor/co2/status","IN RANGE");
        snprintf(msg, 75, "%ld", CO2_3);
        client.publish("sensor/co2/value", msg);
        delay(1000);
      }


      else {
        Serial.println("CO2 is HIGH");
        Serial.println(CO2_3);
        tone(BuzzerPin, 2000, 10000);
        client.publish("sensor/co2/status", "HIGH");
        snprintf(msg, 75, "%ld", CO2_3);
        client.publish("sensor/co2/value", msg);
        delay(1000);
      }
    }
    else
    {
      Serial.println("Reading is NOT ACCURATE. BEGINNING NEW READINGS...");
      Serial.println(CO2_3);
      client.publish("sensor/co2/status", "CO2 Reading is NOT ACCURATE");
      snprintf(msg, 75, "%ld", CO2_3);
      client.publish("sensor/co2/value", msg);
      client.publish("sensor/co2/status", "BEGINNING NEW READINGS");
      delay(1000);
    }
  }
  delay(2000);


}