CCS811 Sensor Problem

Hi everyone! I am trying to use the CCS811 sensor with my Raspberry Pi Zero and I am facing some problems right now.

This is the code I am using:

  GNU nano 5.4                                                                                ccs811.py
import time
import board
import adafruit_ccs811

from board import *
i2c = board.I2C()   # uses board.SCL and board.SDA

ccs =  adafruit_ccs811.CCS811(i2c)
print("CO2: ", ccs.eco2, " TVOC:", ccs.tvoc)

This is the output I am receiving:

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/adafruit_bus_device/i2c_device.py", line 176, in __probe_for_device
    self.i2c.writeto(self.device_address, b"")
  File "/usr/local/lib/python3.9/dist-packages/busio.py", line 175, in writeto
    return self._i2c.writeto(address, buffer, stop=stop)
  File "/usr/local/lib/python3.9/dist-packages/adafruit_blinka/microcontroller/generic_linux/i2c.py", line 52, in writeto
    self._i2c_bus.write_bytes(address, buffer[start:end])
  File "/usr/local/lib/python3.9/dist-packages/Adafruit_PureIO/smbus.py", line 314, in write_bytes
    self._device.write(buf)
OSError: [Errno 121] Remote I/O error

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/dist-packages/adafruit_bus_device/i2c_device.py", line 182, in __probe_for_device
    self.i2c.readfrom_into(self.device_address, result)
  File "/usr/local/lib/python3.9/dist-packages/busio.py", line 165, in readfrom_into
    return self._i2c.readfrom_into(address, buffer, stop=stop)
  File "/usr/local/lib/python3.9/dist-packages/adafruit_blinka/microcontroller/generic_linux/i2c.py", line 59, in readfrom_into
    readin = self._i2c_bus.read_bytes(address, end - start)
  File "/usr/local/lib/python3.9/dist-packages/Adafruit_PureIO/smbus.py", line 181, in read_bytes
    return self._device.read(number)
OSError: [Errno 121] Remote I/O error

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/pi/ccs811.py", line 8, in <module>
    ccs =  adafruit_ccs811.CCS811(i2c)
  File "/usr/local/lib/python3.9/dist-packages/adafruit_ccs811.py", line 130, in __init__
    self.i2c_device = I2CDevice(i2c_bus, address)
  File "/usr/local/lib/python3.9/dist-packages/adafruit_bus_device/i2c_device.py", line 63, in __init__
    self.__probe_for_device()
  File "/usr/local/lib/python3.9/dist-packages/adafruit_bus_device/i2c_device.py", line 185, in __probe_for_device
    raise ValueError("No I2C device at address: 0x%x" % self.device_address)
ValueError: No I2C device at address: 0x5a

I saw that this sensor’s address could be at 0x5a or 0x5b and mine is at 0x5b according to i2cdetect -y 1

0 1 2 3 4 5 6 7 8 9 a b c d e f

00: – – – – – – – –

10: – – – – – – – – – – – – – – – –

20: – – – – – – – – – – – – – – – –

30: – – – – – – – – – – – – – – – –

40: – – – – – – – – – – – – – – – –

50: – – – – – – – – – – – 5b – – – –

60: – – – – – – – – – – – – – – – –

70: – – – – – – – –

It seems like the code is looking into 0x5a and doesn’t encounter anything. Is there a way I can change this?

Thanks for your help, I am still a bit of a newbie to this and still trying to learn! :smiley:

CCS811 is known for issues with clock stretching. It is also known that the Raspberry Pi is not good at handling. look at https://github.com/paulvha/ccs811 and in the documents folder read the CCS8111_clock_stretch.odt for a description. An odt file can be read with ms-word or libreoffice etc.

Thanks for the reply. Going to look into it.

I also looked into the adafruit_ccs811 library that I used and I saw that they put the address there at 0x5A, do you think that could be the reason that when I run the code it says “ValueError: No I2C device at address: 0x5a” when my sensor is at 0x5B.

Hi again! I think I have managed to fix the problem I was having as I can now run the code. However I am now facing a new problem but it is regarding the measurements. When I run the code this is the output I get:

CO2: 0 PPM
TVOC: 0 PPM
Traceback (most recent call last):
  File "/home/pi/ccs2.py", line 9, in <module>
    print("Temp: %0.1f C" % ccs811.temperature)
  File "/usr/local/lib/python3.9/dist-packages/adafruit_ccs811.py", line 243, in           temperature
    ntc_temp = math.log(rntc / 10000.0)
ValueError: math domain error

Any idea on what could be causing this?

That “ValueError: math domain error” is likely due to rntc being either 0 or negative. Could indicate some sort of error reading the value. I also see at the top of that function that the [temperature functionality has been deprecated.](Adafruit_CircuitPython_CCS811/adafruit_ccs811.py at 1e23d41390085d18fd6107ca350a4aa3bf277fa2 · adafruit/Adafruit_CircuitPython_CCS811 · GitHub)

The others are also 0 PPM, it should be an error reading the value but I can’t seem to understand what is wrong. The output is either 0 PPM or this:

Traceback (most recent call last):

File “/home/pi/ccs2.py”, line 8, in

print(“TVOC: %1.0f PPM” % ccs811.tvoc)

TypeError: must be real number, not NoneType

cssvtoc.tvoc could be either an integer or None. You are trying to print the number as floating point (%1.0f) which is not valid for None values. A None value is probably due to an error querying the data or you are trying before it is ready. Did you…

  • - slow down the baudrate for the clock stretching?

    Adding “dtparam=i2c_arm_baudrate=10000” to /boot/config.txt and rebooting worked for me.

  • - wait for css811.data_ready to be True before querying values for 1st time?

    I also had a wait a few more seconds (5) after it said it was ready for some reason


  • I also added checks to toss out-of-range values which I sometime saw. From ccs811 datasheet ([v1-06] 2019-Feb-07) valid ranges are:

  • - CO2 range: 400 - 29206 ppm
  • - VTOC range: 0 - 32768 ppb
  • I have done the first one already. How can I tell if css811.data_ready is True already?

    I just read that the sensor should run for 48 hours to burn it. Could this be a reason why the values are always at 0 PPM? Sorry if these questions are obvious or not well explained, first time using this sensor and still trying to understand what is going on.

    I used to see 0 ppm as well but after some minutes I got other values, to be honest mostly 400 ppm. The 48 hours burn-in should just improve the quality of the reading.

    Is the code you are using very different compared to mine? Still getting only 0s so far.

    Also to add, the pictures are not the best but this is the wiring I have right now.

    SCL - PIN 3

    SDA - PIN 5

    GND - PIN 9

    3.3V - PIN 1

    ccs811_2.jpg

    my code was different. I wrote in c, not Python. Have a look at the earlier mentioned website. It has the working source and installation instructions.

    Thank you so much for your help, will look into it!

    Once you get co2 values of 400 ppm (or greater), then you are probably getting good data. You will need to let it run for a while.

    The answer your your “css811.data_ready is True” question is in the ccs811_init() function (below).

    It is hard to tell from the photo, but are those jumper cables going into a header that is soldered on the CCS811 breakout (good) or through the board into the breadboard (bad)? If the latter, you may not have reliable contact which could cause all sorts of problems.

    Here is what I have been using (extracted from a bigger program). I haven’t tried running this so there is a good chance I screwed something up in my copying chunks of code.

    # more imports may be needed
    import sys
    import logging
    import board
    import adafruit_ccs811
    
    class SensorError(Exception):
        pass
    
    class Sensors:
        def __init__(self, co2, voc):
            self.co2 = co2
            self.voc = voc
    
    def ccs811_init(i2c, address=0x5b):
        ccs811 = adafruit_ccs811.CCS811(i2c, address=address)
        time.sleep(1)
        while not ccs811.data_ready:
            logging.debug('waiting for ccs811 to be ready...')
            time.sleep(1)
    
        # Seems to require a few more seconds to really be ready
        time.sleep(5)
        return ccs811
    
    def read_sensors():
        try:
            co2 = ccs811.eco2
            voc = ccs811.tvoc
        except OSError as e:
            logging.error('Exception reading sensor: %s', e)
            raise SensorError
    
        except RuntimeError as e:
            estr = str(e)
            if estr.startswith('Error'):
                logging.error('Exception: %s', estr)
                raise SensorError
            raise
    
        except Exception:
            logging.error('Exception', exc_info=True)
            raise SensorError
    
        if co2 not in co2_range:
            logging.warning('co2 out of range: %s', co2)
            raise SensorError
    
        if voc not in voc_range:
            logging.warning('voc out of range: %s', voc)
            raise SensorError
    
        return Sensors(co2=co2, voc=voc)
    
    def main():
        logging.basicConfig(level=logging.INFO,
                            format="%(levelname)s:%(message)s")
        logging.info('Starting up')
    
        i2c = board.I2C()
    
        global ccs811
        ccs811 = ccs811_init(i2c)
    
        sensors = read_sensors()
    
        #if you have this from some other source, it might help the ccs811
        #ccs811.set_environmental_data(sensors.humid, sensors.temp)
        time.sleep(1)
    
        while True:
            try:
                sensors = read_sensors()
            except SensorError:
                time.sleep(1)
                continue
    
            log_sensors(sensors) # function not included
            time.sleep(60)
    
    
    if __name__ == "__main__":
        # From ccs811 datasheet [v1-06] 2019-Feb-07
        # - CO2 range: 400 - 29206 ppm
        # - VTOC range: 0 - 32768 ppb
        co2_range = range(400, 29206 + 1)
        voc_range = range(0, 32768 + 1)
    
        try:
            main()
        except Exception:
            logging.critical('Unhandled exception', exc_info=True)
            sys.exit(1)
    

    Screenshot_2023-02-07_15-25-54.png

    It is the second one sadly, this is the material I was given by my school so it’s the only way I could put it together. I will look into your code tomorrow, thanks for your help once again.