CCS811 Weird readings.

Hi,

First of all, I’m sorry if I’m posting this thread in the wrong board. This is my first post so I’m not really experienced here. I hope to be soon!

I’ve been working on a Raspberry Pi project where I gather the readings of a [CCS811 and a [DHT11 sensor and then send them to a MySQL database for readout later.

I use a singular Python script containing the following functions:

  • A 4 way DIP switch to generate a unique ID for the Raspberry Pi (Goal is to use multiple sensors in multiple rooms).

  • A function to only send the data if there is internet connection, if there is no internet connection a LED will start blinking rapidly.

  • Function where I read out values of CCS811 and DHT11 and send it via GET request to DB.

  • Logging all data to a local textfile on the Raspberry PI.

  • After receiving very volatile readings from the CCS811 I started using a Arduino to measure the voltage from the Raspberry pi, singling out the problems that could be causing the weird readings.
  • However, after looking at the voltage and realizing voltage levels aren’t anything out of the order and still getting weird readings… I’m getting stuck. I really do not know what the matter is and I’m starting to think my sensor might be faulty.

    Here is the Python script I use to do all of this. I hope someone can possibly point me in the right direction as to how I can fix this.

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    # By Olivier van Heulen
    # Student at Scalda College
    # Working on Kelvin
    # 206374@student.scalda.nl
    
    import RPi.GPIO as GPIO
    import dht11
    import smbus
    import time
    import urllib3.request
    from datetime import datetime
    import socket
    
    bus = smbus.SMBus(1)
    adress = 0x04
    
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(17, GPIO.OUT)
    GPIO.setup(14, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(15, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(27, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    instance = dht11.DHT11(pin=0x04)
    
    from CCS811_RPi import CCS811_RPi
    
    ccs811 = CCS811_RPi()
    
    http = urllib3.PoolManager()
    url = 'removed for post'
    
    # Do you want to preset sensor baseline? If yes set the value here, otherwise set False
    
    INITIALBASELINE = False
    
    # Set MEAS_MODE (measurement interval)
    
    configuration = 0b100000
    
    
    
    # Set read interval for retriveving last measurement data from the sensor
    
    pause = 60
    
    print 'Checking hardware ID...'
    print ccs811.checkHWID()
    hwid = ccs811.checkHWID()
    print hwid
    if hwid == hex(129):
        print 'Hardware ID is correct'
    else:
        print ('Incorrect hardware ID ', hwid, ', should be 0x81')
    
    
    def internet(host='8.8.8.8', port=53, timeout=3):
        try:
            socket.setdefaulttimeout(timeout)
            socket.socket(socket.AF_INET,
                          socket.SOCK_STREAM).connect((host, port))
            return True
        except Exception, ex:
            return False
    
    
    # print 'MEAS_MODE:',ccs811.readMeasMode()
    
    ccs811.configureSensor(configuration)
    print ('MEAS_MODE:', ccs811.readMeasMode())
    print ('STATUS: ', bin(ccs811.readStatus()))
    print '---------------------------------'
    
    # Use these lines if you need to pre-set and check sensor baseline value
    
    if INITIALBASELINE > 0:
        ccs811.setBaseline(INITIALBASELINE)
        print ccs811.readBaseline()
    
    print 'Waiting 60 seconds for sensor to initialize'
    time.sleep(60)
    print '---------------------------------'
    if internet() == True:
        while 1:
            x = 0
            if GPIO.input(14) == 1:
                x = x + 1
            if GPIO.input(15) == 1:
                x = x + 2
            if GPIO.input(18) == 1:
                x = x + 0x04
            if GPIO.input(27) == 1:
                x = x + 8
            statusbyte = ccs811.readStatus()
    
            print ('STATUS: ', bin(statusbyte))
            print ('Raspberry ID according to DIP: ', x)
            error = ccs811.checkError(statusbyte)
            if error:
                print ('ERROR:', ccs811.checkError(statusbyte))
    
            if not ccs811.checkDataReady(statusbyte):
                GPIO.output(17, 1)
                print 'No new samples are ready'
                print '---------------------------------'
                time.sleep(0.1)
                GPIO.output(17, 0)
                time.sleep(0.1)
                GPIO.output(17, 1)
                time.sleep(0.1)
                GPIO.output(17, 0)
                time.sleep(pause)
                continue
            result1 = instance.read()
            print (result1.temperature)
            print (result1.humidity)
            if result1.temperature > 0:
                if result1.humidity > 0:
                    print("dht gave reading, compensating.")
                    ccs811.setCompensation(result1.temperature, result1.humidity)
            else:
                print("dht didnt give reading, no compensation this time.")
                continue;
            result = ccs811.readAlg()
            if not result:
                print 'Invalid result received'
                time.sleep(pause)
                continue
            GPIO.output(17, 1)
            baseline = ccs811.readBaseline()
    
            print ('eCO2: ', result['eCO2'], ' ppm')
            print ('TVOC: ', result['TVOC'], 'ppb')
    
            # print 'Status register: ',bin(result['status'])
    
            print ('Last error ID: ', result['errorid'])
    
            # print 'RAW data: ',result['raw']
            # print 'Baseline: ',baseline
    
            ppm = result['eCO2']
    
    
            with open('/home/pi/logoffline.txt', 'a') as logger:
                byte_data = bus.read_i2c_block_data(adress, 2)
                voltage = float((byte_data[0] << 8) + byte_data[1])
                print byte_data[0]
                print byte_data[1]
                print 2 * (5 * voltage / 1023)
                logger.write(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S'
                                                         ) + ' eCO2: ' + str(result['eCO2']) + ' TVOC: '
                                 + str(result['TVOC']) + ' error ID: '
                                 + str(result['errorid']) + ' Voltage: '
                                 + str(2 * (5 * voltage / 1023)) + '\n'))
                logger.close
            if result1.is_valid():
                temperature = result1.temperature
                humidity = result1.humidity
    
            try:
    
                # r=http.request('GET',url,fields={'id':x, 'temp':temperature,'hum' :humidity,'co2':ppm})
    
                print r.data.decode('utf-8')
                print '---------------------------------'
            except:
                print 'Error connecting to server, skiping this reading'
                continue
                print '---------------------------------'
    
                time.sleep(0.5)
                GPIO.output(17, 0)
                time.sleep(pause)
            if internet() == False:
                print 'no internet'
                while internet() == False:
                    GPIO.output(17, 1)
                    time.sleep(0.1)
                    GPIO.output(17, 0)
                    time.sleep(0.1)
    
                    print 'still no internett'
    

    and also the library I use for the CCS811:

    #
    # CCS811_RPi
    #
    # Petr Lukas
    # July, 11 2017
    #
    # Version 1.0
    
    import struct, array, time, io, fcntl
    
    # I2C Address
    CCS811_ADDRESS = (0x5B)
    
    # Registers
    CCS811_HW_ID = (0x20)
    CSS811_STATUS = (0x00)
    CSS811_APP_START = (0xF4)
    CSS811_MEAS_MODE = (0x01)
    CSS811_ERROR_ID = (0xE0)
    CSS811_RAW_DATA = (0x03)
    CSS811_ALG_RESULT_DATA = (0x02)
    CSS811_BASELINE = (0x11)
    CSS811_ENV_DATA = (0x05)
    
    # Errors ID
    ERROR = {}
    ERROR[0] = 'WRITE_REG_INVALID'
    ERROR[1] = 'READ_REG_INVALID'
    ERROR[2] = 'MEASMODE_INVALID'
    ERROR[3] = 'MAX_RESISTANCE'
    ERROR[4] = 'HEATER_FAULT'
    ERROR[5] = 'HEATER_SUPPLY'
    
    I2C_SLAVE = 0x0703
    
    CCS811_fw = 0
    CCS811_fr = 0
    
    
    class CCS811_RPi:
        def __init__(self, twi=1, addr=CCS811_ADDRESS):
            global CCS811_fr, CCS811_fw
    
            CCS811_fr = io.open("/dev/i2c-" + str(twi), "rb", buffering=0)
            CCS811_fw = io.open("/dev/i2c-" + str(twi), "wb", buffering=0)
    
            # set device address
            fcntl.ioctl(CCS811_fr, I2C_SLAVE, CCS811_ADDRESS)
            fcntl.ioctl(CCS811_fw, I2C_SLAVE, CCS811_ADDRESS)
            time.sleep(0.015)
    
        # public functions
        def checkHWID(self):
            s = [CCS811_HW_ID]  # Hardware ID
            s2 = bytearray(s)
            CCS811_fw.write(s2)
            time.sleep(0.0625)
    
            data = CCS811_fr.read(1)
    
            buf = array.array('B', data)
            return hex(buf[0])
    
        def readStatus(self):
            time.sleep(0.015)
    
            s = [CSS811_STATUS]
            s2 = bytearray(s)
            CCS811_fw.write(s2)
            time.sleep(0.0625)
    
            data = CCS811_fr.read(1)
            buf = array.array('B', data)
            return buf[0]
    
        def checkError(self, status_byte):
            time.sleep(0.015)
            error_bit = ((status_byte) >> 0) & 1
            if (not error_bit):
                return False
    
            s = [CSS811_ERROR_ID]
            s2 = bytearray(s)
            CCS811_fw.write(s2)
            time.sleep(0.0625)
    
            data = CCS811_fr.read(1)
            buf = array.array('B', data)
            return ERROR[int(buf[0])]
    
        def configureSensor(self, configuration):
            # Switch sensor to application mode
            s = [CSS811_APP_START]
            s2 = bytearray(s)
            CCS811_fw.write(s2)
            time.sleep(0.0625)
    
            s = [CSS811_MEAS_MODE, configuration, 0x00]
            s2 = bytearray(s)
            CCS811_fw.write(s2)
            time.sleep(0.015)
            return
    
        def readMeasMode(self):
            time.sleep(0.015)
            s = [CSS811_MEAS_MODE]
            s2 = bytearray(s)
            CCS811_fw.write(s2)
            time.sleep(0.0625)
    
            data = CCS811_fr.read(1)
            buf = array.array('B', data)
            return bin(buf[0])
    
        def readRaw(self):
            time.sleep(0.015)
            s = [CSS811_RAW_DATA]
            s2 = bytearray(s)
            CCS811_fw.write(s2)
            time.sleep(0.0625)
    
            data = CCS811_fr.read(2)
            buf = array.array('B', data)
            return (buf[0] * 256 + buf[1])
    
        def readAlg(self):
            time.sleep(0.015)
            s = [CSS811_ALG_RESULT_DATA]
            s2 = bytearray(s)
            CCS811_fw.write(s2)
            time.sleep(0.0625)
    
            data = CCS811_fr.read(8)
            buf = array.array('B', data)
            result = {}
            # Read eCO2 value and check if it is valid
            result['eCO2'] = buf[0] * 256 + buf[1]
            if (result['eCO2'] > 8192):
                print('Invalid eCO2 value')
                return False
            # Read TVOC value and check if it is valid
            result['TVOC'] = buf[2] * 256 + buf[3]
            if (result['TVOC'] > 1187):
                print('Invalid TVOC value')
                return False
    
            result['status'] = buf[4]
    
            # Read the last error ID and check if it is valid
            result['errorid'] = buf[5]
            if (result['errorid'] > 5):
                print('Invalid Error ID')
                return False
    
            result['raw'] = buf[6] * 256 + buf[7]
            return result
    
        def readBaseline(self):
            time.sleep(0.015)
            s = [CSS811_BASELINE]
            s2 = bytearray(s)
            CCS811_fw.write(s2)
            time.sleep(0.0625)
    
            data = CCS811_fr.read(2)
            buf = array.array('B', data)
            return (buf[0] * 256 + buf[1])
    
        def checkDataReady(self, status_byte):
            ready_bit = ((status_byte) >> 3) & 1
            if (ready_bit):
                return True
            else:
                return False
    
        def setCompensation(self, temperature, humidity):
            temperature = round(temperature, 2)
            humidity = round(humidity, 2)
            print('Setting compensation to ', temperature, ' C and ', humidity, ' %')
            hum1 = int(humidity // 0.5)
            hum2 = int(humidity * 512 - hum1 * 256)
    
            temperature = temperature + 25
            temp1 = int(temperature // 0.5)
            temp2 = int(temperature * 512 - temp1 * 256)
    
            s = [CSS811_ENV_DATA, hum1, hum2, temp1, temp2, 0x00]
            s2 = bytearray(s)
            CCS811_fw.write(s2)
    
            return
    
        def setBaseline(self, baseline):
            print('Setting baseline to ', baseline)
            buf = [0, 0]
            s = struct.pack('>H', baseline)
            buf[0], buf[1] = struct.unpack('>BB', s)
            print(buf[0])
            print(buf[1])
    
            s = [CSS811_BASELINE, buf[0], buf[1], 0x00]
            s2 = bytearray(s)
            CCS811_fw.write(s2)
            time.sleep(0.015)
    

    TL;DR: I am using a CCS811 sensor to read Co2 sensors but the readings I am getting are not making any sense whatsoever. I am not sure what I’m doing wrong.](DHT11 basic temperature-humidity sensor + extras : ID 386 : Adafruit Industries, Unique & fun DIY electronics and kits)](https://www.sparkfun.com/products/14193)

    Did you give the CCS811 sensor a 48 hour burn-in time, as required?

    After power up, do you give the sensor 20 minutes to warm up and stabilize, before reading it?

    Are the header pins on the breakout board soldered cleanly, with no shorts between pins?

    Tutorial: https://learn.sparkfun.com/tutorials/cc … okup-guide

    Please post examples of the readings.

    jremington:
    Did you give the CCS811 sensor a 48 hour burn-in time, as required?

    After power up, do you give the sensor 20 minutes to warm up and stabilize, before reading it?

    Are the header pins on the breakout board soldered cleanly, with no shorts between pins?

    Tutorial: https://learn.sparkfun.com/tutorials/cc … okup-guide

    Please post examples of the readings.

    Yes, I gave the sensor a burn in time.

    I am reading the sensor from the very moment it boots up but I’m just not really using the first 20 minutes of measurements. Is it necessary to not read the sensor the first 20 minutes?

    These are some readings over the course of 4 days. Measuring every 60 seconds. The spikes to the end of the graph are from testing some functions so you should ignore those.

    https://i.imgur.com/O0mNZhR.png

    This is what really interests me, it looks as if there is a certain formula being put in the graph here…

    https://i.imgur.com/qZCPykE.png

    hi

    I have ordered this board as well and expect it end of the week. I had a look at your code and read some of the reference material and Arduino library. The one aspect that stands out for me on this moment is the compensation.

    SetCompensation : Looking to that library they use env[0], env[1], env[2] and env[3], where your code talks about hum1, hum2, temp1, temp2. The difference is that in the Arduino they set env[1] (hum2) and env[3] (temp2) to zero because “CCS811 only supports increments of 0.5 so bits 7-0 will always be zero”. Looking at the datasheet (page 19), the Arduino library looks correct to me. Your code that Hum2 and temp2 have values set. Could there be your issue ?

    Another aspect I would look at in your code around capturing the compensation. Not sure what instance.read() returns, looks to be a delta instead of current measurement as it compares to zero ???, but even then, why do a “continue” with the “else” that when there is NO compensation measured and skip the rest of the code ??

    I just got a CCS811/BME280 combo and I’m getting weird readings too. I gave it the 48 hour breakin and waited 20 minutes for warup. The readings start off looking reasonable (around 500 ppm CO2 and mid-singe digit VOCs) But the readings slowly creep up more or less linearly from there. After one day, it’s showing CO2 of 5000+ and VOC of 500! And still climbing. In the same room, nothing in the environent has changed. If I power-cycle it, it goes back to the 500 CO2 and 1-4 VOC and then the whole process starts over again.

    Did I get a defective unit?

    Hey,

    I received the CCS811/BME280 unit last week and followed the hookup guide: https://learn.sparkfun.com/tutorials/cc … okup-guide

    Now having similar issues. The temp reading is constantly 5-7 degree C more than should be (it’s more like 22 degrees C where I am)- the rest seems ok - though maybe being thrown off by the wrong temp reading as the CCS811 uses BME280 readings to improve its accuracy.

    This is the print out I get about every other second:

    CO2[491]ppm TVOC[13]ppb temp[29.6]C pressure[101115.52]Pa altitude[18.05]m humidity[34]%

    Waiting to hear back from Sparkfun on this… if anyone has a solution I’d be happy to hear!

    I just wanted to report that I am also getting the “creeping eco2” level issue that everyone else is getting. Has anyone figure out a solution? I have actually used a gas tube to measure the general co2 levels and am getting 500-1000 ppm, while my CCS811 is currently reading anywhere from 2000-5000. Can also reproduce the error outside, where co2 levels should be nowhere near 1000.

    Input to you question…

    I have the SparkFun SCD30 CO2 module. After 3 days of continuous operation (IIC bus used), I powered the module off, then on.

    As you see with your CCS811 reading in the 1000s’ range, I’m now seeing similar values from the SCD30.

    So … I compared this to my CCS811 readings and a second SCD30 module, which report normal values. These modules report within the normal range. Same code and MPU.

    The SCD module also has a temperature and humidity reading, which read normal for both modules.

    My first thought is a CO2 sensor issue. :slight_smile: