From d21a04e8721e9d8b54f31854e8ff31b0e435a604 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Mon, 23 Jul 2018 16:27:15 +0200 Subject: [PATCH] ccs811 completely new from arends/development --- lib/Adafruit_CCS811-master/.travis.yml | 27 ++ .../Adafruit_CCS811.cpp | 280 ++++++++++++++++++ lib/Adafruit_CCS811-master/Adafruit_CCS811.h | 231 +++++++++++++++ lib/Adafruit_CCS811-master/LICENSE | 21 ++ lib/Adafruit_CCS811-master/README.md | 13 + .../CCS811_OLED_Demo/CCS811_OLED_Demo.ino | 80 +++++ .../examples/CCS811_test/CCS811_test.ino | 56 ++++ lib/Adafruit_CCS811-master/library.properties | 9 + sonoff/sonoff.ino | 5 + sonoff/sonoff_post.h | 4 + sonoff/xsns_09_bmp.ino | 6 + sonoff/xsns_14_sht3x.ino | 11 +- sonoff/xsns_31_ccs811.ino | 131 ++++++++ 13 files changed, 873 insertions(+), 1 deletion(-) create mode 100755 lib/Adafruit_CCS811-master/.travis.yml create mode 100755 lib/Adafruit_CCS811-master/Adafruit_CCS811.cpp create mode 100755 lib/Adafruit_CCS811-master/Adafruit_CCS811.h create mode 100755 lib/Adafruit_CCS811-master/LICENSE create mode 100755 lib/Adafruit_CCS811-master/README.md create mode 100755 lib/Adafruit_CCS811-master/examples/CCS811_OLED_Demo/CCS811_OLED_Demo.ino create mode 100755 lib/Adafruit_CCS811-master/examples/CCS811_test/CCS811_test.ino create mode 100755 lib/Adafruit_CCS811-master/library.properties mode change 100644 => 100755 sonoff/sonoff.ino mode change 100644 => 100755 sonoff/sonoff_post.h mode change 100644 => 100755 sonoff/xsns_09_bmp.ino mode change 100644 => 100755 sonoff/xsns_14_sht3x.ino create mode 100644 sonoff/xsns_31_ccs811.ino diff --git a/lib/Adafruit_CCS811-master/.travis.yml b/lib/Adafruit_CCS811-master/.travis.yml new file mode 100755 index 000000000..95efcfaef --- /dev/null +++ b/lib/Adafruit_CCS811-master/.travis.yml @@ -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) \ No newline at end of file diff --git a/lib/Adafruit_CCS811-master/Adafruit_CCS811.cpp b/lib/Adafruit_CCS811-master/Adafruit_CCS811.cpp new file mode 100755 index 000000000..c69cd41f9 --- /dev/null +++ b/lib/Adafruit_CCS811-master/Adafruit_CCS811.cpp @@ -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= 100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +#include + +/*========================================================================= + 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 diff --git a/lib/Adafruit_CCS811-master/LICENSE b/lib/Adafruit_CCS811-master/LICENSE new file mode 100755 index 000000000..860e3e285 --- /dev/null +++ b/lib/Adafruit_CCS811-master/LICENSE @@ -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. \ No newline at end of file diff --git a/lib/Adafruit_CCS811-master/README.md b/lib/Adafruit_CCS811-master/README.md new file mode 100755 index 000000000..04ff8b631 --- /dev/null +++ b/lib/Adafruit_CCS811-master/README.md @@ -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) + + + +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 diff --git a/lib/Adafruit_CCS811-master/examples/CCS811_OLED_Demo/CCS811_OLED_Demo.ino b/lib/Adafruit_CCS811-master/examples/CCS811_OLED_Demo/CCS811_OLED_Demo.ino new file mode 100755 index 000000000..a67d0f1c4 --- /dev/null +++ b/lib/Adafruit_CCS811-master/examples/CCS811_OLED_Demo/CCS811_OLED_Demo.ino @@ -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 +#include +#include + +#include +#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); +} + diff --git a/lib/Adafruit_CCS811-master/examples/CCS811_test/CCS811_test.ino b/lib/Adafruit_CCS811-master/examples/CCS811_test/CCS811_test.ino new file mode 100755 index 000000000..d7503d2ea --- /dev/null +++ b/lib/Adafruit_CCS811-master/examples/CCS811_test/CCS811_test.ino @@ -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); +} \ No newline at end of file diff --git a/lib/Adafruit_CCS811-master/library.properties b/lib/Adafruit_CCS811-master/library.properties new file mode 100755 index 000000000..be5d61361 --- /dev/null +++ b/lib/Adafruit_CCS811-master/library.properties @@ -0,0 +1,9 @@ +name=Adafruit CCS811 Library +version=1.0.0 +author=Adafruit +maintainer=Adafruit +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=* diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino old mode 100644 new mode 100755 index 7818d8170..211c03c13 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -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) diff --git a/sonoff/sonoff_post.h b/sonoff/sonoff_post.h old mode 100644 new mode 100755 index 929d95558..926da7b13 --- a/sonoff/sonoff_post.h +++ b/sonoff/sonoff_post.h @@ -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) diff --git a/sonoff/xsns_09_bmp.ino b/sonoff/xsns_09_bmp.ino old mode 100644 new mode 100755 index 2ffe02ebe..d86bb453e --- a/sonoff/xsns_09_bmp.ino +++ b/sonoff/xsns_09_bmp.ino @@ -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); diff --git a/sonoff/xsns_14_sht3x.ino b/sonoff/xsns_14_sht3x.ino old mode 100644 new mode 100755 index bef289aa3..8356fa4cb --- a/sonoff/xsns_14_sht3x.ino +++ b/sonoff/xsns_14_sht3x.ino @@ -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 \ No newline at end of file +#endif // USE_I2C diff --git a/sonoff/xsns_31_ccs811.ino b/sonoff/xsns_31_ccs811.ino new file mode 100644 index 000000000..e4794a954 --- /dev/null +++ b/sonoff/xsns_31_ccs811.ino @@ -0,0 +1,131 @@ +/* + xsns_31_cc811.ino - CCS811 gas and air quality sensor support for Sonoff-Tasmota + + Copyright (C) 2018 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 . +*/ + +#ifdef USE_I2C +#ifdef USE_CCS811 +/*********************************************************************************************\ + * SGP30 - Gas (TVOC - Total Volatile Organic Compounds) and Air Quality (CO2) + * + * Source: Gerhard Mutz and 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} = , {m} = , {e} = + "{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 + } else { +#ifdef USE_WEBSERVER + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_CCS811, mqtt_data, eCO2, TVOC); +#endif + } + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +#define XSNS_29 + +boolean Xsns29(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