maarten-pennings / CCS811

Arduino library for the CCS811 gas sensor for monitoring indoor air quality.
MIT License
167 stars 47 forks source link

CCS811 does not play nice with ArduinoECCX08 and ArduinoMqttClient libraries #36

Closed martin-c0des closed 3 years ago

martin-c0des commented 4 years ago

On Arduino MKR WiFi 1010, I'm unable to properly initialise and/or use the CCS811 in conjunction with both of the ArduinoECCX08 and ArduinoMqttClient libraries. The basic example runs fine, so I can safely exclude any hardware issues. When I comment out everything that has to do with the ECCX08 and the MqttClient, my code runs fine, however when either of these libraries come into play, the CCS fails to initialize and start, resulting in weird readings like: 54263 and 65503... Could it be an issue with i2c communication? I have the WAKE pin wired to ground... would it make sense to let the Arduino manage it? Any recommendations as to how can I start unraveling this? Thank you, I appreciate your time and effort!

Here's the serial output of what I'm currently getting:

Attempting to connect to SSID: CentralPerk You're connected to the network

Attempting to MQTT broker: xxx.xxxxxxxxx.xxxxxx.amazonaws.com . You're connected to the MQTT broker

ccs811: ping failed (VDD/GND connected? SDA/SCL connected?) setup: CCS811 begin FAILED setup: hardware version: FFFFFFFF setup: bootloader version: FFFFFFFF setup: application version: FFFFFFFF setup: CCS811 start FAILED Publishing new sensor readings: {"temperature":22.7,"humidity":49,"feelsLike":22.3,"co2":54263,"tvoc":65503}

Here's my setup() code:

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

  // Enable I2C
  Wire.begin();

  // Set a callback to get the current time
  // used to validate the servers certificate
  ArduinoBearSSL.onGetTime(getTime);

  // Set the ECCX08 slot to use for the private key
  // and the accompanying public certificate for it
  sslClient.setEccSlot(0, certificate);

  // Crypto Element Setup
  if (!ECCX08.begin()) {
    Serial.println("No ECCX08 present!");
    while (1);
  }

  // Connect to WiFi
  if (WiFi.status() != WL_CONNECTED) {
    connectWiFi();
  }

  // Connect to MQTT Broker
  Serial.print("Attempting to MQTT broker: ");
  Serial.print(broker);
  Serial.println(" ");

  while (!mqttClient.connect(broker, 8883)) {
    // failed, retry
    Serial.print(".");
    delay(5000);
  }
  Serial.println();

  Serial.println("You're connected to the MQTT broker");
  Serial.println();

  // subscribe to a topic
  mqttClient.subscribe("arduino/incoming");

  // Set the message callback, this function is
  // called when the MQTTClient receives a message
  mqttClient.onMessage(onMessageReceived);

  // Enable CCS811
  // Needed for ESP8266 because it doesn't handle I2C clock stretch correctly
  // ccs811.set_i2cdelay(50);
  bool ok = ccs811.begin();
  if(!ok) Serial.println("setup: CCS811 begin FAILED");

  // Print CCS811 versions
  Serial.print("setup: hardware    version: "); Serial.println(ccs811.hardware_version(),HEX);
  Serial.print("setup: bootloader  version: "); Serial.println(ccs811.bootloader_version(),HEX);
  Serial.print("setup: application version: "); Serial.println(ccs811.application_version(),HEX);

  // Start measuring
  ok = ccs811.start(CCS811_MODE_1SEC);
  if(!ok) Serial.println("setup: CCS811 start FAILED");

  // DHT Setup
  dht.begin();

  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);

}

And loop:

void loop() {

  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    return;
  }

  // poll for new MQTT messages and send keep alives
  mqttClient.poll();

  // check for changes and publish a message if values have changed
  if (millis() - lastMillis > 10000) {
    lastMillis = millis();
    updateSensorReadings();
  }

  // read the state of the pushbutton value:
  reading = digitalRead(buttonPin);
   if (reading != lastButtonState) {
      lastDebounceTime = millis();
      lastButtonState = reading;
   }

   if ((millis() - lastDebounceTime) > debounceDelay) {
       if (buttonState != lastButtonState) {
           buttonState = lastButtonState;
           if (buttonState == HIGH) {
                 ledState = !ledState;
                 digitalWrite(ledPin, ledState);
           }
       }
   }

}

The only part in loop that has anything to do with the CCS811 is simply calling this function:

void updateSensorReadings() {
  h = dht.readHumidity();
  t = dht.readTemperature();
  f = round(dht.computeHeatIndex(t, h, false) * 10.0) / 10.0;

  ccs811.read(&co2, &tvoc, NULL, NULL);

  if (h != prevH || t != prevT || f != prevF || co2 != prevCo2 || tvoc != prevTvoc) {
    prevH = h;
    prevT = t;
    prevF = f;
    prevCo2 = co2;
    prevTvoc = prevTvoc;
    publishMessage(t, h, f, co2, tvoc);
  } else {
    Serial.println("Sensor readings unchanged");
  };

  delay(50);

}
maarten-pennings commented 4 years ago

Hi, you are using all kinds of boards and libraries that I don't know. I noticed that the ECCX08 also uses i2c. So, I'm wondering if the ECCX08 library sort of resets the i2c library of the ccs811.

Just to check this, you could maybe move the Wire.begin() call to just before ccs811.begin().

martin-c0des commented 4 years ago

@maarten-pennings Thank you for your comment! I realise it's kind of a mess. Surely enough I'm getting "reset failed" when I moved the Wire.begin() call.

ccs811: reset failed setup: CCS811 begin FAILED setup: hardware version: 12 setup: bootloader version: 1000 setup: application version: 2000

Do you have any advice on how I can mitigate this issue? Or is it simply an incompatibility between the 2 libraries?

Also - feel free to close this issue as I now understand that it's nothing inherently wrong with your library.

maarten-pennings commented 4 years ago

Interesting to see that you get begin FAILED, but then get sensible results for the three versions, so i2c communication is working.

I think this is repairable but I can't do this without having your board per libraries.

What I suspect is that the ECCX08 library and wire.begin compete for i2c control. Make sure you have only one i2c begin, and make sure both use the same pins. You might need to like inside the ECCX08 library.

coelner commented 4 years ago

I took the first ECCX08 library I found and found this: https://github.com/arduino-libraries/ArduinoECCX08/blob/8fb63cea34f2ea58e4cdaa7128db20fea39b73a7/src/ECCX08.cpp#L43

Maybe you can use the Sparkfun library, they do it the right way.