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
|
||||
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)
|
||||
|
|
|
@ -58,6 +58,9 @@ void KNX_CB_Action(message_t const &msg, void *arg);
|
|||
* Provide an image with all supported sensors enabled
|
||||
\*********************************************************************************************/
|
||||
|
||||
|
||||
#define USE_CCS811 // Add I2C code for CCS811 sensor (+2k2 code)
|
||||
|
||||
#ifdef USE_ALL_SENSORS
|
||||
|
||||
#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_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_CCS811 // Add I2C code for CCS811 sensor (+2k2 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_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);
|
||||
#endif // USE_BME680
|
||||
|
||||
|
||||
#ifdef USE_CCS811
|
||||
glob_humidity=bmp_humidity;
|
||||
glob_temperature=(bmp_temperature*4);
|
||||
#endif
|
||||
|
||||
if (json) {
|
||||
char json_humidity[40];
|
||||
snprintf_P(json_humidity, sizeof(json_humidity), PSTR(",\"" D_JSON_HUMIDITY "\":%s"), humidity);
|
||||
|
|
|
@ -101,9 +101,18 @@ void Sht3xShow(boolean json)
|
|||
char types[11];
|
||||
for (byte i = 0; i < sht3x_count; i++) {
|
||||
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(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"
|
||||
|
||||
if (json) {
|
||||
snprintf_P(mqtt_data, sizeof(mqtt_data), JSON_SNS_TEMPHUM, mqtt_data, types, temperature, humidity);
|
||||
#ifdef USE_DOMOTICZ
|
||||
|
@ -159,4 +168,4 @@ boolean Xsns14(byte function)
|
|||
}
|
||||
|
||||
#endif // USE_SHT3X
|
||||
#endif // USE_I2C
|
||||
#endif // USE_I2C
|
||||
|
|
|
@ -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