mirror of https://github.com/arendst/Tasmota.git
commit
dd960acd0b
|
@ -0,0 +1,27 @@
|
||||||
|
language: c
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
# Blacklist
|
||||||
|
branches:
|
||||||
|
except:
|
||||||
|
- gh-pages
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- PRETTYNAME="Adafruit CCS811 Arduino Library"
|
||||||
|
# Optional, will default to "$TRAVIS_BUILD_DIR/Doxyfile"
|
||||||
|
# - DOXYFILE: $TRAVIS_BUILD_DIR/Doxyfile
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/install.sh)
|
||||||
|
|
||||||
|
install:
|
||||||
|
- arduino --install-library "Adafruit SSD1306","Adafruit GFX Library"
|
||||||
|
|
||||||
|
script:
|
||||||
|
- build_main_platforms
|
||||||
|
|
||||||
|
# Generate and deploy documentation
|
||||||
|
after_success:
|
||||||
|
- source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/library_check.sh)
|
||||||
|
- source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/doxy_gen_and_deploy.sh)
|
|
@ -0,0 +1,280 @@
|
||||||
|
#include "Adafruit_CCS811.h"
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@brief Setups the I2C interface and hardware and checks for communication.
|
||||||
|
@param addr Optional I2C address the sensor can be found on. Default is 0x5A
|
||||||
|
@returns True if device is set up, false on any failure
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
sint8_t Adafruit_CCS811::begin(uint8_t addr)
|
||||||
|
{
|
||||||
|
_i2caddr = addr;
|
||||||
|
|
||||||
|
_i2c_init();
|
||||||
|
|
||||||
|
SWReset();
|
||||||
|
delay(100);
|
||||||
|
|
||||||
|
//check that the HW id is correct
|
||||||
|
if(this->read8(CCS811_HW_ID) != CCS811_HW_ID_CODE) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//try to start the app
|
||||||
|
this->write(CCS811_BOOTLOADER_APP_START, NULL, 0);
|
||||||
|
delay(100);
|
||||||
|
|
||||||
|
//make sure there are no errors and we have entered application mode
|
||||||
|
if(checkError()) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
if(!_status.FW_MODE) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
disableInterrupt();
|
||||||
|
|
||||||
|
//default to read every second
|
||||||
|
setDriveMode(CCS811_DRIVE_MODE_1SEC);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@brief sample rate of the sensor.
|
||||||
|
@param mode one of CCS811_DRIVE_MODE_IDLE, CCS811_DRIVE_MODE_1SEC, CCS811_DRIVE_MODE_10SEC, CCS811_DRIVE_MODE_60SEC, CCS811_DRIVE_MODE_250MS.
|
||||||
|
*/
|
||||||
|
void Adafruit_CCS811::setDriveMode(uint8_t mode)
|
||||||
|
{
|
||||||
|
_meas_mode.DRIVE_MODE = mode;
|
||||||
|
this->write8(CCS811_MEAS_MODE, _meas_mode.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@brief enable the data ready interrupt pin on the device.
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
void Adafruit_CCS811::enableInterrupt()
|
||||||
|
{
|
||||||
|
_meas_mode.INT_DATARDY = 1;
|
||||||
|
this->write8(CCS811_MEAS_MODE, _meas_mode.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@brief disable the data ready interrupt pin on the device
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
void Adafruit_CCS811::disableInterrupt()
|
||||||
|
{
|
||||||
|
_meas_mode.INT_DATARDY = 0;
|
||||||
|
this->write8(CCS811_MEAS_MODE, _meas_mode.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@brief checks if data is available to be read.
|
||||||
|
@returns True if data is ready, false otherwise.
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
bool Adafruit_CCS811::available()
|
||||||
|
{
|
||||||
|
_status.set(read8(CCS811_STATUS));
|
||||||
|
if(!_status.DATA_READY)
|
||||||
|
return false;
|
||||||
|
else return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@brief read and store the sensor data. This data can be accessed with getTVOC() and geteCO2()
|
||||||
|
@returns 0 if no error, error code otherwise.
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
uint8_t Adafruit_CCS811::readData()
|
||||||
|
{
|
||||||
|
if(!available())
|
||||||
|
return false;
|
||||||
|
else{
|
||||||
|
uint8_t buf[8];
|
||||||
|
this->read(CCS811_ALG_RESULT_DATA, buf, 8);
|
||||||
|
|
||||||
|
_eCO2 = ((uint16_t)buf[0] << 8) | ((uint16_t)buf[1]);
|
||||||
|
_TVOC = ((uint16_t)buf[2] << 8) | ((uint16_t)buf[3]);
|
||||||
|
|
||||||
|
if(_status.ERROR)
|
||||||
|
return buf[5];
|
||||||
|
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@brief set the humidity and temperature compensation for the sensor.
|
||||||
|
@param humidity the humidity data as a percentage. For 55% humidity, pass in integer 55.
|
||||||
|
@param temperature the temperature in degrees C as a decimal number. For 25.5 degrees C, pass in 25.5
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
void Adafruit_CCS811::setEnvironmentalData(uint8_t humidity, double temperature)
|
||||||
|
{
|
||||||
|
/* Humidity is stored as an unsigned 16 bits in 1/512%RH. The
|
||||||
|
default value is 50% = 0x64, 0x00. As an example 48.5%
|
||||||
|
humidity would be 0x61, 0x00.*/
|
||||||
|
|
||||||
|
/* Temperature is stored as an unsigned 16 bits integer in 1/512
|
||||||
|
degrees; there is an offset: 0 maps to -25°C. The default value is
|
||||||
|
25°C = 0x64, 0x00. As an example 23.5% temperature would be
|
||||||
|
0x61, 0x00.
|
||||||
|
The internal algorithm uses these values (or default values if
|
||||||
|
not set by the application) to compensate for changes in
|
||||||
|
relative humidity and ambient temperature.*/
|
||||||
|
|
||||||
|
uint8_t hum_perc = humidity << 1;
|
||||||
|
|
||||||
|
float fractional = modf(temperature, &temperature);
|
||||||
|
uint16_t temp_high = (((uint16_t)temperature + 25) << 9);
|
||||||
|
uint16_t temp_low = ((uint16_t)(fractional / 0.001953125) & 0x1FF);
|
||||||
|
|
||||||
|
uint16_t temp_conv = (temp_high | temp_low);
|
||||||
|
|
||||||
|
uint8_t buf[] = {hum_perc, 0x00,
|
||||||
|
(uint8_t)((temp_conv >> 8) & 0xFF), (uint8_t)(temp_conv & 0xFF)};
|
||||||
|
|
||||||
|
this->write(CCS811_ENV_DATA, buf, 4);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@brief calculate the temperature using the onboard NTC resistor.
|
||||||
|
@returns temperature as a double.
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
double Adafruit_CCS811::calculateTemperature()
|
||||||
|
{
|
||||||
|
uint8_t buf[4];
|
||||||
|
this->read(CCS811_NTC, buf, 4);
|
||||||
|
|
||||||
|
uint32_t vref = ((uint32_t)buf[0] << 8) | buf[1];
|
||||||
|
uint32_t vntc = ((uint32_t)buf[2] << 8) | buf[3];
|
||||||
|
|
||||||
|
//from ams ccs811 app note
|
||||||
|
uint32_t rntc = vntc * CCS811_REF_RESISTOR / vref;
|
||||||
|
|
||||||
|
double ntc_temp;
|
||||||
|
ntc_temp = log((double)rntc / CCS811_REF_RESISTOR); // 1
|
||||||
|
ntc_temp /= 3380; // 2
|
||||||
|
ntc_temp += 1.0 / (25 + 273.15); // 3
|
||||||
|
ntc_temp = 1.0 / ntc_temp; // 4
|
||||||
|
ntc_temp -= 273.15; // 5
|
||||||
|
return ntc_temp - _tempOffset;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@brief set interrupt thresholds
|
||||||
|
@param low_med the level below which an interrupt will be triggered.
|
||||||
|
@param med_high the level above which the interrupt will ge triggered.
|
||||||
|
@param hysteresis optional histeresis level. Defaults to 50
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
void Adafruit_CCS811::setThresholds(uint16_t low_med, uint16_t med_high, uint8_t hysteresis)
|
||||||
|
{
|
||||||
|
uint8_t buf[] = {(uint8_t)((low_med >> 8) & 0xF), (uint8_t)(low_med & 0xF),
|
||||||
|
(uint8_t)((med_high >> 8) & 0xF), (uint8_t)(med_high & 0xF), hysteresis};
|
||||||
|
|
||||||
|
this->write(CCS811_THRESHOLDS, buf, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@brief trigger a software reset of the device
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
void Adafruit_CCS811::SWReset()
|
||||||
|
{
|
||||||
|
//reset sequence from the datasheet
|
||||||
|
uint8_t seq[] = {0x11, 0xE5, 0x72, 0x8A};
|
||||||
|
this->write(CCS811_SW_RESET, seq, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@brief read the status register and store any errors.
|
||||||
|
@returns the error bits from the status register of the device.
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
bool Adafruit_CCS811::checkError()
|
||||||
|
{
|
||||||
|
_status.set(read8(CCS811_STATUS));
|
||||||
|
return _status.ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@brief write one byte of data to the specified register
|
||||||
|
@param reg the register to write to
|
||||||
|
@param value the value to write
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
void Adafruit_CCS811::write8(byte reg, byte value)
|
||||||
|
{
|
||||||
|
this->write(reg, &value, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@brief read one byte of data from the specified register
|
||||||
|
@param reg the register to read
|
||||||
|
@returns one byte of register data
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
uint8_t Adafruit_CCS811::read8(byte reg)
|
||||||
|
{
|
||||||
|
uint8_t ret;
|
||||||
|
this->read(reg, &ret, 1);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Adafruit_CCS811::_i2c_init()
|
||||||
|
{
|
||||||
|
Wire.begin();
|
||||||
|
#ifdef ESP8266
|
||||||
|
Wire.setClockStretchLimit(1000);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Adafruit_CCS811::read(uint8_t reg, uint8_t *buf, uint8_t num)
|
||||||
|
{
|
||||||
|
uint8_t value;
|
||||||
|
uint8_t pos = 0;
|
||||||
|
|
||||||
|
//on arduino we need to read in 32 byte chunks
|
||||||
|
while(pos < num){
|
||||||
|
|
||||||
|
uint8_t read_now = min((uint8_t)32, (uint8_t)(num - pos));
|
||||||
|
Wire.beginTransmission((uint8_t)_i2caddr);
|
||||||
|
Wire.write((uint8_t)reg + pos);
|
||||||
|
Wire.endTransmission();
|
||||||
|
Wire.requestFrom((uint8_t)_i2caddr, read_now);
|
||||||
|
|
||||||
|
for(int i=0; i<read_now; i++){
|
||||||
|
buf[pos] = Wire.read();
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Adafruit_CCS811::write(uint8_t reg, uint8_t *buf, uint8_t num)
|
||||||
|
{
|
||||||
|
Wire.beginTransmission((uint8_t)_i2caddr);
|
||||||
|
Wire.write((uint8_t)reg);
|
||||||
|
Wire.write((uint8_t *)buf, num);
|
||||||
|
Wire.endTransmission();
|
||||||
|
}
|
|
@ -0,0 +1,231 @@
|
||||||
|
#ifndef LIB_ADAFRUIT_CCS811_H
|
||||||
|
#define LIB_ADAFRUIT_CCS811_H
|
||||||
|
|
||||||
|
#if (ARDUINO >= 100)
|
||||||
|
#include "Arduino.h"
|
||||||
|
#else
|
||||||
|
#include "WProgram.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
|
||||||
|
/*=========================================================================
|
||||||
|
I2C ADDRESS/BITS
|
||||||
|
-----------------------------------------------------------------------*/
|
||||||
|
#define CCS811_ADDRESS (0x5A)
|
||||||
|
/*=========================================================================*/
|
||||||
|
|
||||||
|
/*=========================================================================
|
||||||
|
REGISTERS
|
||||||
|
-----------------------------------------------------------------------*/
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CCS811_STATUS = 0x00,
|
||||||
|
CCS811_MEAS_MODE = 0x01,
|
||||||
|
CCS811_ALG_RESULT_DATA = 0x02,
|
||||||
|
CCS811_RAW_DATA = 0x03,
|
||||||
|
CCS811_ENV_DATA = 0x05,
|
||||||
|
CCS811_NTC = 0x06,
|
||||||
|
CCS811_THRESHOLDS = 0x10,
|
||||||
|
CCS811_BASELINE = 0x11,
|
||||||
|
CCS811_HW_ID = 0x20,
|
||||||
|
CCS811_HW_VERSION = 0x21,
|
||||||
|
CCS811_FW_BOOT_VERSION = 0x23,
|
||||||
|
CCS811_FW_APP_VERSION = 0x24,
|
||||||
|
CCS811_ERROR_ID = 0xE0,
|
||||||
|
CCS811_SW_RESET = 0xFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
//bootloader registers
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CCS811_BOOTLOADER_APP_ERASE = 0xF1,
|
||||||
|
CCS811_BOOTLOADER_APP_DATA = 0xF2,
|
||||||
|
CCS811_BOOTLOADER_APP_VERIFY = 0xF3,
|
||||||
|
CCS811_BOOTLOADER_APP_START = 0xF4
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CCS811_DRIVE_MODE_IDLE = 0x00,
|
||||||
|
CCS811_DRIVE_MODE_1SEC = 0x01,
|
||||||
|
CCS811_DRIVE_MODE_10SEC = 0x02,
|
||||||
|
CCS811_DRIVE_MODE_60SEC = 0x03,
|
||||||
|
CCS811_DRIVE_MODE_250MS = 0x04,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*=========================================================================*/
|
||||||
|
|
||||||
|
#define CCS811_HW_ID_CODE 0x81
|
||||||
|
|
||||||
|
#define CCS811_REF_RESISTOR 100000
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@brief Class that stores state and functions for interacting with CCS811 gas sensor chips
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
class Adafruit_CCS811 {
|
||||||
|
public:
|
||||||
|
//constructors
|
||||||
|
Adafruit_CCS811(void) {};
|
||||||
|
~Adafruit_CCS811(void) {};
|
||||||
|
|
||||||
|
sint8_t begin(uint8_t addr = CCS811_ADDRESS);
|
||||||
|
|
||||||
|
void setEnvironmentalData(uint8_t humidity, double temperature);
|
||||||
|
|
||||||
|
//calculate temperature based on the NTC register
|
||||||
|
double calculateTemperature();
|
||||||
|
|
||||||
|
void setThresholds(uint16_t low_med, uint16_t med_high, uint8_t hysteresis = 50);
|
||||||
|
|
||||||
|
void SWReset();
|
||||||
|
|
||||||
|
void setDriveMode(uint8_t mode);
|
||||||
|
void enableInterrupt();
|
||||||
|
void disableInterrupt();
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@brief returns the stored total volatile organic compounds measurement. This does does not read the sensor. To do so, call readData()
|
||||||
|
@returns TVOC measurement as 16 bit integer
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
uint16_t getTVOC() { return _TVOC; }
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@brief returns the stored estimated carbon dioxide measurement. This does does not read the sensor. To do so, call readData()
|
||||||
|
@returns eCO2 measurement as 16 bit integer
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
uint16_t geteCO2() { return _eCO2; }
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/*!
|
||||||
|
@brief set the temperature compensation offset for the device. This is needed to offset errors in NTC measurements.
|
||||||
|
@param offset the offset to be added to temperature measurements.
|
||||||
|
*/
|
||||||
|
/**************************************************************************/
|
||||||
|
void setTempOffset(float offset) { _tempOffset = offset; }
|
||||||
|
|
||||||
|
//check if data is available to be read
|
||||||
|
bool available();
|
||||||
|
uint8_t readData();
|
||||||
|
|
||||||
|
bool checkError();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t _i2caddr;
|
||||||
|
float _tempOffset;
|
||||||
|
|
||||||
|
uint16_t _TVOC;
|
||||||
|
uint16_t _eCO2;
|
||||||
|
|
||||||
|
void write8(byte reg, byte value);
|
||||||
|
void write16(byte reg, uint16_t value);
|
||||||
|
uint8_t read8(byte reg);
|
||||||
|
|
||||||
|
void read(uint8_t reg, uint8_t *buf, uint8_t num);
|
||||||
|
void write(uint8_t reg, uint8_t *buf, uint8_t num);
|
||||||
|
void _i2c_init();
|
||||||
|
|
||||||
|
/*=========================================================================
|
||||||
|
REGISTER BITFIELDS
|
||||||
|
-----------------------------------------------------------------------*/
|
||||||
|
// The status register
|
||||||
|
struct status {
|
||||||
|
|
||||||
|
/* 0: no error
|
||||||
|
* 1: error has occurred
|
||||||
|
*/
|
||||||
|
uint8_t ERROR: 1;
|
||||||
|
|
||||||
|
// reserved : 2
|
||||||
|
|
||||||
|
/* 0: no samples are ready
|
||||||
|
* 1: samples are ready
|
||||||
|
*/
|
||||||
|
uint8_t DATA_READY: 1;
|
||||||
|
uint8_t APP_VALID: 1;
|
||||||
|
|
||||||
|
// reserved : 2
|
||||||
|
|
||||||
|
/* 0: boot mode, new firmware can be loaded
|
||||||
|
* 1: application mode, can take measurements
|
||||||
|
*/
|
||||||
|
uint8_t FW_MODE: 1;
|
||||||
|
|
||||||
|
void set(uint8_t data){
|
||||||
|
ERROR = data & 0x01;
|
||||||
|
DATA_READY = (data >> 3) & 0x01;
|
||||||
|
APP_VALID = (data >> 4) & 0x01;
|
||||||
|
FW_MODE = (data >> 7) & 0x01;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
status _status;
|
||||||
|
|
||||||
|
//measurement and conditions register
|
||||||
|
struct meas_mode {
|
||||||
|
// reserved : 2
|
||||||
|
|
||||||
|
/* 0: interrupt mode operates normally
|
||||||
|
* 1: Interrupt mode (if enabled) only asserts the nINT signal (driven low) if the new
|
||||||
|
ALG_RESULT_DATA crosses one of the thresholds set in the THRESHOLDS register
|
||||||
|
by more than the hysteresis value (also in the THRESHOLDS register)
|
||||||
|
*/
|
||||||
|
uint8_t INT_THRESH: 1;
|
||||||
|
|
||||||
|
/* 0: int disabled
|
||||||
|
* 1: The nINT signal is asserted (driven low) when a new sample is ready in
|
||||||
|
ALG_RESULT_DATA. The nINT signal will stop being driven low when
|
||||||
|
ALG_RESULT_DATA is read on the I²C interface.
|
||||||
|
*/
|
||||||
|
uint8_t INT_DATARDY: 1;
|
||||||
|
|
||||||
|
uint8_t DRIVE_MODE: 3;
|
||||||
|
|
||||||
|
uint8_t get(){
|
||||||
|
return (INT_THRESH << 2) | (INT_DATARDY << 3) | (DRIVE_MODE << 4);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
meas_mode _meas_mode;
|
||||||
|
|
||||||
|
struct error_id {
|
||||||
|
/* The CCS811 received an I²C write request addressed to this station but with
|
||||||
|
invalid register address ID */
|
||||||
|
uint8_t WRITE_REG_INVALID: 1;
|
||||||
|
|
||||||
|
/* The CCS811 received an I²C read request to a mailbox ID that is invalid */
|
||||||
|
uint8_t READ_REG_INVALID: 1;
|
||||||
|
|
||||||
|
/* The CCS811 received an I²C request to write an unsupported mode to
|
||||||
|
MEAS_MODE */
|
||||||
|
uint8_t MEASMODE_INVALID: 1;
|
||||||
|
|
||||||
|
/* The sensor resistance measurement has reached or exceeded the maximum
|
||||||
|
range */
|
||||||
|
uint8_t MAX_RESISTANCE: 1;
|
||||||
|
|
||||||
|
/* The Heater current in the CCS811 is not in range */
|
||||||
|
uint8_t HEATER_FAULT: 1;
|
||||||
|
|
||||||
|
/* The Heater voltage is not being applied correctly */
|
||||||
|
uint8_t HEATER_SUPPLY: 1;
|
||||||
|
|
||||||
|
void set(uint8_t data){
|
||||||
|
WRITE_REG_INVALID = data & 0x01;
|
||||||
|
READ_REG_INVALID = (data & 0x02) >> 1;
|
||||||
|
MEASMODE_INVALID = (data & 0x04) >> 2;
|
||||||
|
MAX_RESISTANCE = (data & 0x08) >> 3;
|
||||||
|
HEATER_FAULT = (data & 0x10) >> 4;
|
||||||
|
HEATER_SUPPLY = (data & 0x20) >> 5;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
error_id _error_id;
|
||||||
|
|
||||||
|
/*=========================================================================*/
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2017 Adafruit Industries
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,13 @@
|
||||||
|
# Adafruit CCS811 Library [![Build Status](https://travis-ci.org/adafruit/Adafruit_CCS811.svg?branch=master)](https://travis-ci.org/adafruit/Adafruit_CCS811)
|
||||||
|
|
||||||
|
<img src="https://cdn-shop.adafruit.com/970x728/3566-00.jpg" height="300"/>
|
||||||
|
|
||||||
|
This is a library for the Adafruit CCS811 gas sensor breakout board:
|
||||||
|
* https://www.adafruit.com/product/3566
|
||||||
|
|
||||||
|
Check out the links above for our tutorials and wiring diagrams. This chip uses I2C to communicate
|
||||||
|
|
||||||
|
Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!
|
||||||
|
|
||||||
|
Written by Dean Miller for Adafruit Industries.
|
||||||
|
MIT license, all text above must be included in any redistribution
|
|
@ -0,0 +1,80 @@
|
||||||
|
/* This demo shows how to display the CCS811 readings on an Adafruit I2C OLED.
|
||||||
|
* (We used a Feather + OLED FeatherWing)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <Adafruit_GFX.h>
|
||||||
|
|
||||||
|
#include <Adafruit_SSD1306.h>
|
||||||
|
#include "Adafruit_CCS811.h"
|
||||||
|
|
||||||
|
Adafruit_CCS811 ccs;
|
||||||
|
Adafruit_SSD1306 display = Adafruit_SSD1306();
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
if(!ccs.begin()){
|
||||||
|
Serial.println("Failed to start sensor! Please check your wiring.");
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
|
||||||
|
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x32)
|
||||||
|
|
||||||
|
// Show image buffer on the display hardware.
|
||||||
|
// Since the buffer is intialized with an Adafruit splashscreen
|
||||||
|
// internally, this will display the splashscreen.
|
||||||
|
display.display();
|
||||||
|
delay(500);
|
||||||
|
|
||||||
|
// Clear the buffer.
|
||||||
|
display.clearDisplay();
|
||||||
|
display.display();
|
||||||
|
|
||||||
|
//calibrate temperature sensor
|
||||||
|
while(!ccs.available());
|
||||||
|
float temp = ccs.calculateTemperature();
|
||||||
|
ccs.setTempOffset(temp - 25.0);
|
||||||
|
|
||||||
|
Serial.println("IO test");
|
||||||
|
|
||||||
|
// text display tests
|
||||||
|
display.setTextSize(1);
|
||||||
|
display.setTextColor(WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
display.setCursor(0,0);
|
||||||
|
if(ccs.available()){
|
||||||
|
display.clearDisplay();
|
||||||
|
float temp = ccs.calculateTemperature();
|
||||||
|
if(!ccs.readData()){
|
||||||
|
display.print("eCO2: ");
|
||||||
|
Serial.print("eCO2: ");
|
||||||
|
float eCO2 = ccs.geteCO2();
|
||||||
|
display.print(eCO2);
|
||||||
|
Serial.print(eCO2);
|
||||||
|
|
||||||
|
display.print(" ppm\nTVOC: ");
|
||||||
|
Serial.print(" ppm, TVOC: ");
|
||||||
|
float TVOC = ccs.getTVOC();
|
||||||
|
display.print(TVOC);
|
||||||
|
Serial.print(TVOC);
|
||||||
|
|
||||||
|
Serial.print(" ppb Temp:");
|
||||||
|
display.print(" ppb\nTemp: ");
|
||||||
|
Serial.println(temp);
|
||||||
|
display.println(temp);
|
||||||
|
display.display();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
Serial.println("ERROR!");
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
/***************************************************************************
|
||||||
|
This is a library for the CCS811 air
|
||||||
|
|
||||||
|
This sketch reads the sensor
|
||||||
|
|
||||||
|
Designed specifically to work with the Adafruit CCS811 breakout
|
||||||
|
----> http://www.adafruit.com/products/3566
|
||||||
|
|
||||||
|
These sensors use I2C to communicate. The device's I2C address is 0x5A
|
||||||
|
|
||||||
|
Adafruit invests time and resources providing this open source code,
|
||||||
|
please support Adafruit andopen-source hardware by purchasing products
|
||||||
|
from Adafruit!
|
||||||
|
|
||||||
|
Written by Dean Miller for Adafruit Industries.
|
||||||
|
BSD license, all text above must be included in any redistribution
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "Adafruit_CCS811.h"
|
||||||
|
|
||||||
|
Adafruit_CCS811 ccs;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
Serial.println("CCS811 test");
|
||||||
|
|
||||||
|
if(!ccs.begin()){
|
||||||
|
Serial.println("Failed to start sensor! Please check your wiring.");
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//calibrate temperature sensor
|
||||||
|
while(!ccs.available());
|
||||||
|
float temp = ccs.calculateTemperature();
|
||||||
|
ccs.setTempOffset(temp - 25.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
if(ccs.available()){
|
||||||
|
float temp = ccs.calculateTemperature();
|
||||||
|
if(!ccs.readData()){
|
||||||
|
Serial.print("CO2: ");
|
||||||
|
Serial.print(ccs.geteCO2());
|
||||||
|
Serial.print("ppm, TVOC: ");
|
||||||
|
Serial.print(ccs.getTVOC());
|
||||||
|
Serial.print("ppb Temp:");
|
||||||
|
Serial.println(temp);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
Serial.println("ERROR!");
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delay(500);
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
name=Adafruit CCS811 Library
|
||||||
|
version=1.0.0
|
||||||
|
author=Adafruit
|
||||||
|
maintainer=Adafruit <info@adafruit.com>
|
||||||
|
sentence=This is a library for the Adafruit CCS811 I2C gas sensor breakout.
|
||||||
|
paragraph=This is a library for the Adafruit CCS811 I2C gas sensor breakou.
|
||||||
|
category=Sensors
|
||||||
|
url=https://github.com/adafruit/Adafruit_CCS811
|
||||||
|
architectures=*
|
|
@ -198,6 +198,11 @@ char log_data[LOGSZ]; // Logging
|
||||||
char web_log[WEB_LOG_SIZE] = {'\0'}; // Web log buffer
|
char web_log[WEB_LOG_SIZE] = {'\0'}; // Web log buffer
|
||||||
String backlog[MAX_BACKLOG]; // Command backlog
|
String backlog[MAX_BACKLOG]; // Command backlog
|
||||||
|
|
||||||
|
#ifdef USE_CCS811
|
||||||
|
uint8_t glob_humidity=0;
|
||||||
|
sint16_t glob_temperature=-9999;
|
||||||
|
#endif
|
||||||
|
|
||||||
/********************************************************************************************/
|
/********************************************************************************************/
|
||||||
|
|
||||||
char* Format(char* output, const char* input, int size)
|
char* Format(char* output, const char* input, int size)
|
||||||
|
|
|
@ -58,6 +58,9 @@ void KNX_CB_Action(message_t const &msg, void *arg);
|
||||||
* Provide an image with all supported sensors enabled
|
* Provide an image with all supported sensors enabled
|
||||||
\*********************************************************************************************/
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#define USE_CCS811 // Add I2C code for CCS811 sensor (+2k2 code)
|
||||||
|
|
||||||
#ifdef USE_ALL_SENSORS
|
#ifdef USE_ALL_SENSORS
|
||||||
|
|
||||||
#define USE_ADC_VCC // Display Vcc in Power status. Disable for use as Analog input on selected devices
|
#define USE_ADC_VCC // Display Vcc in Power status. Disable for use as Analog input on selected devices
|
||||||
|
@ -71,6 +74,7 @@ void KNX_CB_Action(message_t const &msg, void *arg);
|
||||||
#define USE_BMP // Add I2C code for BMP085/BMP180/BMP280/BME280 sensor (+4k code)
|
#define USE_BMP // Add I2C code for BMP085/BMP180/BMP280/BME280 sensor (+4k code)
|
||||||
#define USE_BME680 // Add additional support for BME680 sensor using Bosch BME680 library (+4k code)
|
#define USE_BME680 // Add additional support for BME680 sensor using Bosch BME680 library (+4k code)
|
||||||
#define USE_SGP30 // Add I2C code for SGP30 sensor (+1k1 code)
|
#define USE_SGP30 // Add I2C code for SGP30 sensor (+1k1 code)
|
||||||
|
#define USE_CCS811 // Add I2C code for CCS811 sensor (+2k2 code)
|
||||||
#define USE_BH1750 // Add I2C code for BH1750 sensor (+0k5 code)
|
#define USE_BH1750 // Add I2C code for BH1750 sensor (+0k5 code)
|
||||||
#define USE_VEML6070 // Add I2C code for VEML6070 sensor (+0k5 code)
|
#define USE_VEML6070 // Add I2C code for VEML6070 sensor (+0k5 code)
|
||||||
#define USE_TSL2561 // Add I2C code for TSL2561 sensor using library Adafruit TSL2561 Arduino (+1k2 code)
|
#define USE_TSL2561 // Add I2C code for TSL2561 sensor using library Adafruit TSL2561 Arduino (+1k2 code)
|
||||||
|
|
|
@ -495,6 +495,12 @@ void BmpShow(boolean json)
|
||||||
dtostrfd(bmp_gas_resistance, 2, gas_resistance);
|
dtostrfd(bmp_gas_resistance, 2, gas_resistance);
|
||||||
#endif // USE_BME680
|
#endif // USE_BME680
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef USE_CCS811
|
||||||
|
glob_humidity=bmp_humidity;
|
||||||
|
glob_temperature=(bmp_temperature*4);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (json) {
|
if (json) {
|
||||||
char json_humidity[40];
|
char json_humidity[40];
|
||||||
snprintf_P(json_humidity, sizeof(json_humidity), PSTR(",\"" D_JSON_HUMIDITY "\":%s"), humidity);
|
snprintf_P(json_humidity, sizeof(json_humidity), PSTR(",\"" D_JSON_HUMIDITY "\":%s"), humidity);
|
||||||
|
|
|
@ -101,9 +101,18 @@ void Sht3xShow(boolean json)
|
||||||
char types[11];
|
char types[11];
|
||||||
for (byte i = 0; i < sht3x_count; i++) {
|
for (byte i = 0; i < sht3x_count; i++) {
|
||||||
if (Sht3xRead(t, h, sht3x_sensors[i].address)) {
|
if (Sht3xRead(t, h, sht3x_sensors[i].address)) {
|
||||||
|
|
||||||
|
#ifdef USE_CCS811
|
||||||
|
if (i==0) {
|
||||||
|
glob_humidity=h;
|
||||||
|
glob_temperature=(t*4);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
dtostrfd(t, Settings.flag2.temperature_resolution, temperature);
|
dtostrfd(t, Settings.flag2.temperature_resolution, temperature);
|
||||||
dtostrfd(h, Settings.flag2.humidity_resolution, humidity);
|
dtostrfd(h, Settings.flag2.humidity_resolution, humidity);
|
||||||
snprintf_P(types, sizeof(types), PSTR("%s-0x%02X"), sht3x_sensors[i].types, sht3x_sensors[i].address); // "SHT3X-0xXX"
|
snprintf_P(types, sizeof(types), PSTR("%s-0x%02X"), sht3x_sensors[i].types, sht3x_sensors[i].address); // "SHT3X-0xXX"
|
||||||
|
|
||||||
if (json) {
|
if (json) {
|
||||||
snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMPHUM, mqtt_data, types, temperature, humidity);
|
snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMPHUM, mqtt_data, types, temperature, humidity);
|
||||||
#ifdef USE_DOMOTICZ
|
#ifdef USE_DOMOTICZ
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
xsns_31_ccs811.ino - CCS811 gas and air quality sensor support for Sonoff-Tasmota
|
||||||
|
|
||||||
|
Copyright (C) 2018 Gerhard Mutz and Theo Arends
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_I2C
|
||||||
|
#ifdef USE_CCS811
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* SGP30 - Gas (TVOC - Total Volatile Organic Compounds) and Air Quality (CO2)
|
||||||
|
*
|
||||||
|
* Source: Adafruit
|
||||||
|
*
|
||||||
|
* I2C Address: 0x5A assumes ADDR connected to Gnd, Wake also must be grounded
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
#include "Adafruit_CCS811.h"
|
||||||
|
|
||||||
|
Adafruit_CCS811 ccs;
|
||||||
|
uint8_t CCS811_ready;
|
||||||
|
uint8_t CCS811_type;
|
||||||
|
uint16_t eCO2;
|
||||||
|
uint16_t TVOC;
|
||||||
|
uint8_t tcnt,ecnt;
|
||||||
|
|
||||||
|
/********************************************************************************************/
|
||||||
|
#define EVERYNSECONDS 5
|
||||||
|
|
||||||
|
void CCS811Update() // Perform every n second
|
||||||
|
{
|
||||||
|
tcnt+=1;
|
||||||
|
if (tcnt>=EVERYNSECONDS) {
|
||||||
|
tcnt=0;
|
||||||
|
CCS811_ready = 0;
|
||||||
|
if (!CCS811_type) {
|
||||||
|
sint8_t res=ccs.begin(CCS811_ADDRESS);
|
||||||
|
if (!res) {
|
||||||
|
CCS811_type = 1;
|
||||||
|
snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "CCS811", 0x5A);
|
||||||
|
AddLog(LOG_LEVEL_DEBUG);
|
||||||
|
} else {
|
||||||
|
//snprintf_P(log_data, sizeof(log_data), "CCS811 init failed: %d",res);
|
||||||
|
//AddLog(LOG_LEVEL_DEBUG);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ccs.available()) {
|
||||||
|
if (!ccs.readData()){
|
||||||
|
TVOC=ccs.getTVOC();
|
||||||
|
eCO2=ccs.geteCO2();
|
||||||
|
CCS811_ready = 1;
|
||||||
|
if (glob_humidity!=0 && glob_temperature!=-9999) {
|
||||||
|
double gtmp=glob_temperature;
|
||||||
|
ccs.setEnvironmentalData(glob_humidity,gtmp/4);
|
||||||
|
}
|
||||||
|
ecnt=0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// failed, count up
|
||||||
|
ecnt+=1;
|
||||||
|
if (ecnt>6) {
|
||||||
|
// after 30 seconds, restart
|
||||||
|
ccs.begin(CCS811_ADDRESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char HTTP_SNS_CCS811[] PROGMEM = "%s"
|
||||||
|
"{s}CCS811 " D_ECO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}" // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
|
||||||
|
"{s}CCS811 " D_TVOC "{m}%d " D_UNIT_PARTS_PER_BILLION "{e}";
|
||||||
|
|
||||||
|
void CCS811Show(boolean json)
|
||||||
|
{
|
||||||
|
if (CCS811_ready) {
|
||||||
|
if (json) {
|
||||||
|
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"CCS811\":{\"" D_JSON_ECO2 "\":%d,\"" D_JSON_TVOC "\":%d}"), mqtt_data,eCO2,TVOC);
|
||||||
|
#ifdef USE_DOMOTICZ
|
||||||
|
if (0 == tele_period) DomoticzSensor(DZ_AIRQUALITY, eCO2);
|
||||||
|
#endif // USE_DOMOTICZ
|
||||||
|
#ifdef USE_WEBSERVER
|
||||||
|
} else {
|
||||||
|
snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_CCS811, mqtt_data, eCO2, TVOC);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Interface
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
#define XSNS_31
|
||||||
|
|
||||||
|
boolean Xsns31(byte function)
|
||||||
|
{
|
||||||
|
boolean result = false;
|
||||||
|
|
||||||
|
if (i2c_flg) {
|
||||||
|
switch (function) {
|
||||||
|
case FUNC_EVERY_SECOND:
|
||||||
|
CCS811Update();
|
||||||
|
break;
|
||||||
|
case FUNC_JSON_APPEND:
|
||||||
|
CCS811Show(1);
|
||||||
|
break;
|
||||||
|
#ifdef USE_WEBSERVER
|
||||||
|
case FUNC_WEB_APPEND:
|
||||||
|
CCS811Show(0);
|
||||||
|
break;
|
||||||
|
#endif // USE_WEBSERVER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // USE_CCS811
|
||||||
|
#endif // USE_I2C
|
Loading…
Reference in New Issue