diff --git a/lib/Adafruit_SGP30-1.0.0.13/.github/ISSUE_TEMPLATE.md b/lib/Adafruit_SGP30-1.0.0.13/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..f0e26146f --- /dev/null +++ b/lib/Adafruit_SGP30-1.0.0.13/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,46 @@ +Thank you for opening an issue on an Adafruit Arduino library repository. To +improve the speed of resolution please review the following guidelines and +common troubleshooting steps below before creating the issue: + +- **Do not use GitHub issues for troubleshooting projects and issues.** Instead use + the forums at http://forums.adafruit.com to ask questions and troubleshoot why + something isn't working as expected. In many cases the problem is a common issue + that you will more quickly receive help from the forum community. GitHub issues + are meant for known defects in the code. If you don't know if there is a defect + in the code then start with troubleshooting on the forum first. + +- **If following a tutorial or guide be sure you didn't miss a step.** Carefully + check all of the steps and commands to run have been followed. Consult the + forum if you're unsure or have questions about steps in a guide/tutorial. + +- **For Arduino projects check these very common issues to ensure they don't apply**: + + - For uploading sketches or communicating with the board make sure you're using + a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes + very hard to tell the difference between a data and charge cable! Try using the + cable with other devices or swapping to another cable to confirm it is not + the problem. + + - **Be sure you are supplying adequate power to the board.** Check the specs of + your board and plug in an external power supply. In many cases just + plugging a board into your computer is not enough to power it and other + peripherals. + + - **Double check all soldering joints and connections.** Flakey connections + cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints. + + - **Ensure you are using an official Arduino or Adafruit board.** We can't + guarantee a clone board will have the same functionality and work as expected + with this code and don't support them. + +If you're sure this issue is a defect in the code and checked the steps above +please fill in the following fields to provide enough troubleshooting information. +You may delete the guideline and text above to just leave the following details: + +- Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE** + +- Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO + VERSION HERE** + +- List the steps to reproduce the problem below (if possible attach a sketch or + copy the sketch code in too): **LIST REPRO STEPS BELOW** diff --git a/lib/Adafruit_SGP30-1.0.0.13/.github/PULL_REQUEST_TEMPLATE.md b/lib/Adafruit_SGP30-1.0.0.13/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..7b641eb86 --- /dev/null +++ b/lib/Adafruit_SGP30-1.0.0.13/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,26 @@ +Thank you for creating a pull request to contribute to Adafruit's GitHub code! +Before you open the request please review the following guidelines and tips to +help it be more easily integrated: + +- **Describe the scope of your change--i.e. what the change does and what parts + of the code were modified.** This will help us understand any risks of integrating + the code. + +- **Describe any known limitations with your change.** For example if the change + doesn't apply to a supported platform of the library please mention it. + +- **Please run any tests or examples that can exercise your modified code.** We + strive to not break users of the code and running tests/examples helps with this + process. + +Thank you again for contributing! We will try to test and integrate the change +as soon as we can, but be aware we have many GitHub repositories to manage and +can't immediately respond to every request. There is no need to bump or check in +on a pull request (it will clutter the discussion of the request). + +Also don't be worried if the request is closed or not integrated--sometimes the +priorities of Adafruit's GitHub code (education, ease of use) might not match the +priorities of the pull request. Don't fret, the open source community thrives on +forks and GitHub makes it easy to keep your changes in a forked repo. + +After reviewing the guidelines above you can delete this text from the pull request. diff --git a/lib/Adafruit_SGP30-1.0.0.13/.gitignore b/lib/Adafruit_SGP30-1.0.0.13/.gitignore new file mode 100644 index 000000000..7f189125f --- /dev/null +++ b/lib/Adafruit_SGP30-1.0.0.13/.gitignore @@ -0,0 +1,4 @@ +*~ +Doxyfile* +doxygen_sqlite3.db +html \ No newline at end of file diff --git a/lib/Adafruit_SGP30-1.0.0.13/.travis.yml b/lib/Adafruit_SGP30-1.0.0.13/.travis.yml new file mode 100644 index 000000000..428f3434e --- /dev/null +++ b/lib/Adafruit_SGP30-1.0.0.13/.travis.yml @@ -0,0 +1,27 @@ +language: c +sudo: false + +# Blacklist +branches: + except: + - gh-pages + +env: + global: + - PRETTYNAME="Adafruit SGP30 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 ILI9341","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_SGP30-1.0.0.13/Adafruit_SGP30.cpp b/lib/Adafruit_SGP30-1.0.0.13/Adafruit_SGP30.cpp new file mode 100644 index 000000000..b2ccbe8da --- /dev/null +++ b/lib/Adafruit_SGP30-1.0.0.13/Adafruit_SGP30.cpp @@ -0,0 +1,243 @@ +/*! + * @file Adafruit_SGP30.cpp + * + * @mainpage Adafruit SGP30 gas sensor driver + * + * @section intro_sec Introduction + * + * This is the documentation for Adafruit's SGP30 driver for the + * Arduino platform. It is designed specifically to work with the + * Adafruit SGP30 breakout: http://www.adafruit.com/products/3709 + * + * These sensors use I2C to communicate, 2 pins (SCL+SDA) are required + * to interface with the breakout. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * + * @section author Author + * Written by Ladyada for Adafruit Industries. + * + * @section license License + * BSD license, all text here must be included in any redistribution. + * + */ + + +#if ARDUINO >= 100 + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +#include "Adafruit_SGP30.h" + +//#define I2C_DEBUG + +/**************************************************************************/ +/*! + @brief Instantiates a new SGP30 class +*/ +/**************************************************************************/ +Adafruit_SGP30::Adafruit_SGP30() { +} + +/**************************************************************************/ +/*! + @brief Setups the hardware and detects a valid SGP30. Initializes I2C + then reads the serialnumber and checks that we are talking to an SGP30 + @param theWire Optional pointer to I2C interface, otherwise use Wire + @returns True if SGP30 found on I2C, False if something went wrong! +*/ +/**************************************************************************/ +boolean Adafruit_SGP30::begin(TwoWire *theWire) { + _i2caddr = SGP30_I2CADDR_DEFAULT; + if (theWire == NULL) { + _i2c = &Wire; + } else { + _i2c = theWire; + } + + _i2c->begin(); + + + uint8_t command[2]; + command[0] = 0x36; + command[1] = 0x82; + if (! readWordFromCommand(command, 2, 10, serialnumber, 3)) + return false; + + uint16_t featureset; + command[0] = 0x20; + command[1] = 0x2F; + if (! readWordFromCommand(command, 2, 10, &featureset, 1)) + return false; + //Serial.print("Featureset 0x"); Serial.println(featureset, HEX); + if (featureset != SGP30_FEATURESET) + return false; + if (! IAQinit()) + return false; + + return true; +} + +/**************************************************************************/ +/*! + @brief Commands the sensor to begin the IAQ algorithm. Must be called after startup. + @returns True if command completed successfully, false if something went wrong! +*/ +/**************************************************************************/ +boolean Adafruit_SGP30::IAQinit(void) { + uint8_t command[2]; + command[0] = 0x20; + command[1] = 0x03; + return readWordFromCommand(command, 2, 10); +} + +/**************************************************************************/ +/*! + @brief Commands the sensor to take a single eCO2/VOC measurement. Places results in {@link TVOC} and {@link eCO2} + @returns True if command completed successfully, false if something went wrong! +*/ +/**************************************************************************/ +boolean Adafruit_SGP30::IAQmeasure(void) { + uint8_t command[2]; + command[0] = 0x20; + command[1] = 0x08; + uint16_t reply[2]; + if (! readWordFromCommand(command, 2, 12, reply, 2)) + return false; + TVOC = reply[1]; + eCO2 = reply[0]; + return true; +} + +/**************************************************************************/ +/*! + @brief Request baseline calibration values for both CO2 and TVOC IAQ calculations. Places results in parameter memory locaitons. + @param eco2_base A pointer to a uint16_t which we will save the calibration value to + @param tvoc_base A pointer to a uint16_t which we will save the calibration value to + @returns True if command completed successfully, false if something went wrong! +*/ +/**************************************************************************/ +boolean Adafruit_SGP30::getIAQBaseline(uint16_t *eco2_base, uint16_t *tvoc_base) { + uint8_t command[2]; + command[0] = 0x20; + command[1] = 0x15; + uint16_t reply[2]; + if (! readWordFromCommand(command, 2, 10, reply, 2)) + return false; + *eco2_base = reply[0]; + *tvoc_base = reply[1]; + return true; +} + +/**************************************************************************/ +/*! + @brief Assign baseline calibration values for both CO2 and TVOC IAQ calculations. + @param eco2_base A uint16_t which we will save the calibration value from + @param tvoc_base A uint16_t which we will save the calibration value from + @returns True if command completed successfully, false if something went wrong! +*/ +/**************************************************************************/ +boolean Adafruit_SGP30::setIAQBaseline(uint16_t eco2_base, uint16_t tvoc_base) { + uint8_t command[8]; + command[0] = 0x20; + command[1] = 0x1e; + command[2] = tvoc_base >> 8; + command[3] = tvoc_base & 0xFF; + command[4] = generateCRC(command+2, 2); + command[5] = eco2_base >> 8; + command[6] = eco2_base & 0xFF; + command[7] = generateCRC(command+5, 2); + + return readWordFromCommand(command, 8, 10); +} + +/**************************************************************************/ +/*! + @brief I2C low level interfacing +*/ +/**************************************************************************/ + + +boolean Adafruit_SGP30::readWordFromCommand(uint8_t command[], uint8_t commandLength, uint16_t delayms, uint16_t *readdata, uint8_t readlen) +{ + uint8_t data; + + _i2c->beginTransmission(_i2caddr); + +#ifdef I2C_DEBUG + Serial.print("\t\t-> "); +#endif + + for (uint8_t i=0; iwrite(command[i]); +#ifdef I2C_DEBUG + Serial.print("0x"); Serial.print(command[i], HEX); Serial.print(", "); +#endif + } +#ifdef I2C_DEBUG + Serial.println(); +#endif + _i2c->endTransmission(); + + delay(delayms); + + if (readlen == 0) + return true; + + uint8_t replylen = readlen * (SGP30_WORD_LEN +1); + if (_i2c->requestFrom(_i2caddr, replylen) != replylen) + return false; + uint8_t replybuffer[replylen]; +#ifdef I2C_DEBUG + Serial.print("\t\t<- "); +#endif + for (uint8_t i=0; iread(); +#ifdef I2C_DEBUG + Serial.print("0x"); Serial.print(replybuffer[i], HEX); Serial.print(", "); +#endif + } + +#ifdef I2C_DEBUG + Serial.println(); +#endif + + for (uint8_t i=0; i + +// the i2c address +#define SGP30_I2CADDR_DEFAULT 0x58 ///< SGP30 has only one I2C address + +// commands and constants +#define SGP30_FEATURESET 0x0020 ///< The required set for this library +#define SGP30_CRC8_POLYNOMIAL 0x31 ///< Seed for SGP30's CRC polynomial +#define SGP30_CRC8_INIT 0xFF ///< Init value for CRC +#define SGP30_WORD_LEN 2 ///< 2 bytes per word + +/**************************************************************************/ +/*! Class that stores state and functions for interacting with SGP30 Gas Sensor */ +/**************************************************************************/ +class Adafruit_SGP30 { + public: + Adafruit_SGP30(); + boolean begin(TwoWire *theWire = NULL); + boolean IAQinit(void); + boolean IAQmeasure(void); + + boolean getIAQBaseline(uint16_t *eco2_base, uint16_t *tvoc_base); + boolean setIAQBaseline(uint16_t eco2_base, uint16_t tvoc_base); + + /** + * The last measurement of the IAQ-calculated Total Volatile Organic Compounds in ppb. This value is set when you call {@link IAQmeasure()} + */ + uint16_t TVOC; + + /** + * The last measurement of the IAQ-calculated equivalent CO2 in ppm. This value is set when you call {@link IAQmeasure()} + */ + uint16_t eCO2; + + /** + * The 48-bit serial number, this value is set when you call {@link begin()} + */ + uint16_t serialnumber[3]; + private: + TwoWire *_i2c; + uint8_t _i2caddr; + + void write(uint8_t address, uint8_t *data, uint8_t n); + void read(uint8_t address, uint8_t *data, uint8_t n); + boolean readWordFromCommand(uint8_t command[], uint8_t commandLength, uint16_t delay, uint16_t *readdata = NULL, uint8_t readlen = 0); + uint8_t generateCRC(uint8_t data[], uint8_t datalen); +}; diff --git a/lib/Adafruit_SGP30-1.0.0.13/README.md b/lib/Adafruit_SGP30-1.0.0.13/README.md new file mode 100644 index 000000000..44056b5c8 --- /dev/null +++ b/lib/Adafruit_SGP30-1.0.0.13/README.md @@ -0,0 +1,18 @@ +Adafruit_SGP30 +================ + +This is the Adafruit SGP30 Gas / Air Quality I2C sensor library + +Tested and works great with the Aadafruit SGP30 Breakout Board + * http://www.adafruit.com/products/3709 + +This chip uses I2C to communicate, 2 pins are required to interface + +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing +products from Adafruit! + +Written by Limor Fried for Adafruit Industries. +BSD license, check license.txt for more information +All text above must be included in any redistribution + diff --git a/lib/Adafruit_SGP30-1.0.0.13/examples/sgp30test/sgp30test.ino b/lib/Adafruit_SGP30-1.0.0.13/examples/sgp30test/sgp30test.ino new file mode 100644 index 000000000..6b9b3ea05 --- /dev/null +++ b/lib/Adafruit_SGP30-1.0.0.13/examples/sgp30test/sgp30test.ino @@ -0,0 +1,45 @@ +#include +#include "Adafruit_SGP30.h" + +Adafruit_SGP30 sgp; + +void setup() { + Serial.begin(9600); + Serial.println("SGP30 test"); + + if (! sgp.begin()){ + Serial.println("Sensor not found :("); + while (1); + } + Serial.print("Found SGP30 serial #"); + Serial.print(sgp.serialnumber[0], HEX); + Serial.print(sgp.serialnumber[1], HEX); + Serial.println(sgp.serialnumber[2], HEX); + + // If you have a baseline measurement from before you can assign it to start, to 'self-calibrate' + //sgp.setIAQBaseline(0x8E68, 0x8F41); // Will vary for each sensor! +} + +int counter = 0; +void loop() { + if (! sgp.IAQmeasure()) { + Serial.println("Measurement failed"); + return; + } + Serial.print("TVOC "); Serial.print(sgp.TVOC); Serial.print(" ppb\t"); + Serial.print("eCO2 "); Serial.print(sgp.eCO2); Serial.println(" ppm"); + delay(1000); + + counter++; + if (counter == 30) { + counter = 0; + + uint16_t TVOC_base, eCO2_base; + if (! sgp.getIAQBaseline(&eCO2_base, &TVOC_base)) { + Serial.println("Failed to get baseline readings"); + return; + } + Serial.print("****Baseline values: eCO2: 0x"); Serial.print(eCO2_base, HEX); + Serial.print(" & TVOC: 0x"); Serial.println(TVOC_base, HEX); + } +} \ No newline at end of file diff --git a/lib/Adafruit_SGP30-1.0.0.13/library.properties b/lib/Adafruit_SGP30-1.0.0.13/library.properties new file mode 100644 index 000000000..3520b4d38 --- /dev/null +++ b/lib/Adafruit_SGP30-1.0.0.13/library.properties @@ -0,0 +1,9 @@ +name=Adafruit SGP30 Sensor +version=1.0.2 +author=Adafruit +maintainer=Adafruit +sentence=This is an Arduino library for the Adafruit SGP30 Gas / Air Quality Sensor +paragraph=This is an Arduino library for the Adafruit SGP30 Gas / Air Quality Sensor +category=Sensors +url=https://github.com/adafruit/Adafruit_SGP30 +architectures=* diff --git a/lib/Adafruit_SGP30-1.0.0.13/license.txt b/lib/Adafruit_SGP30-1.0.0.13/license.txt new file mode 100644 index 000000000..f6a0f22b8 --- /dev/null +++ b/lib/Adafruit_SGP30-1.0.0.13/license.txt @@ -0,0 +1,26 @@ +Software License Agreement (BSD License) + +Copyright (c) 2012, Adafruit Industries +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holders nor the +names of its contributors may be used to endorse or promote products +derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index e65516123..35ae88f27 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -2,11 +2,12 @@ * Add 16 timers using commands Timer and Timers (#1091) * Add commands Timer 0 to clear timer and Timer 1..16 to copy timer * Add optional Timer configuration webpage to be enabled in user_config.h with define USE_TIMERS_WEB - * Change MQTT response topic for Energy changes from ENERGY to SENSOR (#2229, #2251) * Add Home Assistant MQTT Discovery for Buttons and change SetOption19 response (#2277) + * Add support for SGP30 gas and air quality sensor (#2307) * Change webpage parameter communication - * Change default Reset configuration time from 4 seconds to 40 seconds on Button hold (#2268) * Change Timer parameter Device to more obvious Output + * Change MQTT response topic for Energy changes from ENERGY to SENSOR (#2229, #2251) + * Change default Reset configuration time from 4 seconds to 40 seconds on Button hold (#2268) * * 5.12.0h * Add optional Arduino OTA support to be enabled in user_config.h (#1998) diff --git a/sonoff/i18n.h b/sonoff/i18n.h index dcc7024a0..12db1d541 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -111,6 +111,7 @@ #define D_JSON_TIME "Time" #define D_JSON_TODAY "Today" #define D_JSON_TOTAL "Total" +#define D_JSON_TVOC "TVOC" #define D_JSON_TYPE "Type" #define D_JSON_UPTIME "Uptime" #define D_JSON_UTC_TIME "UTC" @@ -381,6 +382,8 @@ enum UnitNames { UNIT_MILLIAMPERE, UNIT_MILLISECOND, UNIT_MINUTE, + UNIT_PPB, + UNIT_PPD, UNIT_PPM, UNIT_PERCENTAGE, UNIT_PRESSURE, @@ -399,6 +402,8 @@ const char kUnitNames[] PROGMEM = D_UNIT_MILLIAMPERE "|" D_UNIT_MILLISECOND "|" D_UNIT_MINUTE "|" + D_UNIT_PARTS_PER_BILLION "|" + D_UNIT_PARTS_PER_DECILITER "|" D_UNIT_PARTS_PER_MILLION "|" "%|" D_UNIT_PRESSURE "|" @@ -475,7 +480,7 @@ const char HTTP_SNS_PRESSURE[] PROGMEM = "%s{s}%s " D_PRESSURE "{m}%s " D_UNIT_P const char HTTP_SNS_SEAPRESSURE[] PROGMEM = "%s{s}%s " D_PRESSUREATSEALEVEL "{m}%s " D_UNIT_PRESSURE "{e}"; // {s} = , {m} = , {e} = const char HTTP_SNS_ANALOG[] PROGMEM = "%s{s}%s " D_ANALOG_INPUT "%d{m}%d{e}"; // {s} = , {m} = , {e} = -#if defined(USE_MHZ19) || defined(USE_SENSEAIR) +#if defined(USE_MHZ19) || defined(USE_SENSEAIR) || defined(USE_SGP30) const char HTTP_SNS_CO2[] PROGMEM = "%s{s}%s " D_CO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}"; // {s} = , {m} = , {e} = #endif // USE_WEBSERVER diff --git a/sonoff/language/cs-CZ.h b/sonoff/language/cs-CZ.h index 8e953810e..9f2740ecb 100644 --- a/sonoff/language/cs-CZ.h +++ b/sonoff/language/cs-CZ.h @@ -142,6 +142,7 @@ #define D_TOPIC "Topic" #define D_TRANSMIT "Odešli" #define D_TRUE "Pravda" +#define D_TVOC "TVOC" #define D_UPGRADE "aktualizace" #define D_UPLOAD "Nahrání..." #define D_UPTIME "Uptime" @@ -437,6 +438,7 @@ #define D_UNIT_MILLIAMPERE "mA" #define D_UNIT_MILLISECOND "ms" #define D_UNIT_MINUTE "Min" +#define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" #define D_UNIT_PARTS_PER_MILLION "ppm" #define D_UNIT_PRESSURE "hPa" diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index 7e50360d0..45040412e 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -142,6 +142,7 @@ #define D_TOPIC "topic" #define D_TRANSMIT "Übertragen" #define D_TRUE "wahr" +#define D_TVOC "TVOC" #define D_UPGRADE "update" #define D_UPLOAD "Upload" #define D_UPTIME "Laufzeit" @@ -437,6 +438,7 @@ #define D_UNIT_MILLIAMPERE "mA" #define D_UNIT_MILLISECOND "ms" #define D_UNIT_MINUTE "min" +#define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" #define D_UNIT_PARTS_PER_MILLION "ppm" #define D_UNIT_PRESSURE "hPa" diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index c0ead99f8..dadd68f85 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -142,6 +142,7 @@ #define D_TOPIC "Topic" #define D_TRANSMIT "Transmit" #define D_TRUE "True" +#define D_TVOC "TVOC" #define D_UPGRADE "upgrade" #define D_UPLOAD "Upload" #define D_UPTIME "Uptime" @@ -437,6 +438,7 @@ #define D_UNIT_MILLIAMPERE "mA" #define D_UNIT_MILLISECOND "ms" #define D_UNIT_MINUTE "Min" +#define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" #define D_UNIT_PARTS_PER_MILLION "ppm" #define D_UNIT_PRESSURE "hPa" diff --git a/sonoff/language/es-AR.h b/sonoff/language/es-AR.h index 891a313ab..ae9acf887 100644 --- a/sonoff/language/es-AR.h +++ b/sonoff/language/es-AR.h @@ -142,6 +142,7 @@ #define D_TOPIC "Topic" #define D_TRANSMIT "Transmitir" #define D_TRUE "Verdadero" +#define D_TVOC "TVOC" #define D_UPGRADE "Actualización" #define D_UPLOAD "Carga" #define D_UPTIME "Tiempo Encendido" @@ -437,6 +438,7 @@ #define D_UNIT_MILLIAMPERE "mA" #define D_UNIT_MILLISECOND "ms" #define D_UNIT_MINUTE "Min" +#define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" #define D_UNIT_PARTS_PER_MILLION "ppm" #define D_UNIT_PRESSURE "hPa" diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index e021604de..d5a62db80 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -142,6 +142,7 @@ #define D_TOPIC "Topic" #define D_TRANSMIT "Transmettre" #define D_TRUE "Vrai" +#define D_TVOC "TVOC" #define D_UPGRADE "upgrade" #define D_UPLOAD "Upload" #define D_UPTIME "Uptime" @@ -437,6 +438,7 @@ #define D_UNIT_MILLIAMPERE "mA" #define D_UNIT_MILLISECOND "ms" #define D_UNIT_MINUTE "Min" +#define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" #define D_UNIT_PARTS_PER_MILLION "ppm" #define D_UNIT_PRESSURE "hPa" diff --git a/sonoff/language/hu-HU.h b/sonoff/language/hu-HU.h index 6288b743a..f4dc7a0c9 100644 --- a/sonoff/language/hu-HU.h +++ b/sonoff/language/hu-HU.h @@ -142,6 +142,7 @@ #define D_TOPIC "Téma" #define D_TRANSMIT "Továbbít" #define D_TRUE "Igaz" +#define D_TVOC "TVOC" #define D_UPGRADE "frissítés" #define D_UPLOAD "Feltöltés" #define D_UPTIME "Üzemidő" @@ -437,6 +438,7 @@ #define D_UNIT_MILLIAMPERE "mA" #define D_UNIT_MILLISECOND "ms" #define D_UNIT_MINUTE "p" +#define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" #define D_UNIT_PARTS_PER_MILLION "ppm" #define D_UNIT_PRESSURE "hPa" diff --git a/sonoff/language/it-IT.h b/sonoff/language/it-IT.h index 64383eec4..8a3a80702 100644 --- a/sonoff/language/it-IT.h +++ b/sonoff/language/it-IT.h @@ -142,6 +142,7 @@ #define D_TOPIC "Topic" #define D_TRANSMIT "Trasmesso" #define D_TRUE "True" +#define D_TVOC "TVOC" #define D_UPGRADE "aggiornamento" #define D_UPLOAD "Invio" #define D_UPTIME "Uptime" @@ -437,6 +438,7 @@ #define D_UNIT_MILLIAMPERE "mA" #define D_UNIT_MILLISECOND "ms" #define D_UNIT_MINUTE "Min" +#define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" #define D_UNIT_PARTS_PER_MILLION "ppm" #define D_UNIT_PRESSURE "hPa" diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index 2d1fbaf31..507213f07 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -142,6 +142,7 @@ #define D_TOPIC "Topic" // Onderwerp #define D_TRANSMIT "Verzend" #define D_TRUE "Waar" +#define D_TVOC "TVOC" #define D_UPGRADE "opwaarderen" #define D_UPLOAD "Verzenden" #define D_UPTIME "Bedrijfstijd" @@ -437,6 +438,7 @@ #define D_UNIT_MILLIAMPERE "mA" #define D_UNIT_MILLISECOND "ms" #define D_UNIT_MINUTE "Min" +#define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" #define D_UNIT_PARTS_PER_MILLION "ppm" #define D_UNIT_PRESSURE "hPa" diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index 9cd364d43..856e682bf 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -142,6 +142,7 @@ #define D_TOPIC "Temat" #define D_TRANSMIT "Wyślij" #define D_TRUE "Prawda" +#define D_TVOC "TVOC" #define D_UPGRADE "aktualizacji" #define D_UPLOAD "Wgraj" #define D_UPTIME "Uptime" @@ -437,6 +438,7 @@ #define D_UNIT_MILLIAMPERE "mA" #define D_UNIT_MILLISECOND "ms" #define D_UNIT_MINUTE "Min" +#define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" #define D_UNIT_PARTS_PER_MILLION "ppm" #define D_UNIT_PRESSURE "hPa" diff --git a/sonoff/language/pt-PT.h b/sonoff/language/pt-PT.h index 2f4d40a1d..482e40474 100644 --- a/sonoff/language/pt-PT.h +++ b/sonoff/language/pt-PT.h @@ -142,6 +142,7 @@ #define D_TOPIC "Tópico" #define D_TRANSMIT "Transmitir" #define D_TRUE "Verdadeiro" +#define D_TVOC "TVOC" #define D_UPGRADE "Atualizar" #define D_UPLOAD "Enviar" #define D_UPTIME "Tempo de Atividade" @@ -437,6 +438,7 @@ #define D_UNIT_MILLIAMPERE "mA" #define D_UNIT_MILLISECOND "ms" #define D_UNIT_MINUTE "Min" +#define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" #define D_UNIT_PARTS_PER_MILLION "ppm" #define D_UNIT_PRESSURE "hPa" diff --git a/sonoff/language/ru-RU.h b/sonoff/language/ru-RU.h index aad061b0c..ee84a50b0 100644 --- a/sonoff/language/ru-RU.h +++ b/sonoff/language/ru-RU.h @@ -142,6 +142,7 @@ #define D_TOPIC "Топик" #define D_TRANSMIT "Передать" #define D_TRUE "Истина" +#define D_TVOC "TVOC" #define D_UPGRADE "обновление" #define D_UPLOAD "Загрузить" #define D_UPTIME "Uptime" @@ -437,6 +438,7 @@ #define D_UNIT_MILLIAMPERE "мА" #define D_UNIT_MILLISECOND "мс" #define D_UNIT_MINUTE "мин" +#define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "ppd" #define D_UNIT_PARTS_PER_MILLION "ppm" #define D_UNIT_PRESSURE "гПа" diff --git a/sonoff/language/zh-CN.h b/sonoff/language/zh-CN.h index 4fadd8592..a105a9c3a 100644 --- a/sonoff/language/zh-CN.h +++ b/sonoff/language/zh-CN.h @@ -142,6 +142,7 @@ #define D_TOPIC "主题" #define D_TRANSMIT "发送" #define D_TRUE "True" +#define D_TVOC "TVOC" #define D_UPGRADE "升级" #define D_UPLOAD "上传" #define D_UPTIME "运行时间" @@ -437,6 +438,7 @@ #define D_UNIT_MILLIAMPERE "毫安" #define D_UNIT_MILLISECOND "毫秒" #define D_UNIT_MINUTE "分" +#define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "每分升" #define D_UNIT_PARTS_PER_MILLION "ppm" #define D_UNIT_PRESSURE "百帕" diff --git a/sonoff/language/zh-TW.h b/sonoff/language/zh-TW.h index f6b8e8ecd..118e0d719 100644 --- a/sonoff/language/zh-TW.h +++ b/sonoff/language/zh-TW.h @@ -142,6 +142,7 @@ #define D_TOPIC "主題" #define D_TRANSMIT "發送" #define D_TRUE "True" +#define D_TVOC "TVOC" #define D_UPGRADE "升級" #define D_UPLOAD "上傳" #define D_UPTIME "運行時間" @@ -437,6 +438,7 @@ #define D_UNIT_MILLIAMPERE "毫安" #define D_UNIT_MILLISECOND "毫秒" #define D_UNIT_MINUTE "分" +#define D_UNIT_PARTS_PER_BILLION "ppb" #define D_UNIT_PARTS_PER_DECILITER "每分升" #define D_UNIT_PARTS_PER_MILLION "ppm" #define D_UNIT_PRESSURE "百帕" diff --git a/sonoff/sonoff_post.h b/sonoff/sonoff_post.h index 09b4836ba..67678c6e2 100644 --- a/sonoff/sonoff_post.h +++ b/sonoff/sonoff_post.h @@ -45,6 +45,7 @@ void WifiWpsStatusCallback(wps_cb_status status); #define USE_HTU // Add I2C code for HTU21/SI7013/SI7020/SI7021 sensor (+1k5 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 Adafruit Sensor and BME680 libraries (+6k code) +#define USE_SGP30 // Add I2C code for SGP30 sensor (+4k 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) @@ -101,6 +102,9 @@ void WifiWpsStatusCallback(wps_cb_status status); #ifdef USE_EMULATION #undef USE_EMULATION // Disable Wemo or Hue emulation #endif +#ifdef USE_TIMERS +#undef USE_TIMERS // Disable support for up to 16 timers +#endif #ifdef USE_PZEM004T #undef USE_PZEM004T // Disable PZEM004T energy sensor #endif diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 68cafc6be..5b274624a 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -206,6 +206,7 @@ #define USE_HTU // Add I2C code for HTU21/SI7013/SI7020/SI7021 sensor (+1k5 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 Adafruit Sensor and BME680 libraries (+6k code) + #define USE_SGP30 // Add I2C code for SGP30 sensor (+1k1 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 Joba_Tsl2561 (+2k3 code) diff --git a/sonoff/xsns_21_sgp30.ino b/sonoff/xsns_21_sgp30.ino new file mode 100644 index 000000000..205c34437 --- /dev/null +++ b/sonoff/xsns_21_sgp30.ino @@ -0,0 +1,115 @@ +/* + xsns_21_sgp30.ino - SGP30 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_SGP30 +/*********************************************************************************************\ + * SGP30 - Gas (TVOC - Total Volatile Organic Compounds) and Air Quality (CO2) + * + * Source: Gerhard Mutz and Adafruit Industries + * + * I2C Address: 0x58 +\*********************************************************************************************/ + +#include "Adafruit_SGP30.h" +Adafruit_SGP30 sgp; + +uint8_t sgp30_type = 0; +uint8_t sgp30_ready = 0; +uint8_t sgp30_counter = 0; + +/********************************************************************************************/ + +void Sgp30Update() // Perform every second to ensure proper operation of the baseline compensation algorithm +{ + sgp30_ready = 0; + if (!sgp30_type) { + if (sgp.begin()) { + sgp30_type = 1; +// snprintf_P(log_data, sizeof(log_data), PSTR("SGP: Serialnumber 0x%04X-0x%04X-0x%04X"), sgp.serialnumber[0], sgp.serialnumber[1], sgp.serialnumber[2]); +// AddLog(LOG_LEVEL_DEBUG); + snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "SGP30", 0x58); + AddLog(LOG_LEVEL_DEBUG); + } + } else { + if (!sgp.IAQmeasure()) return; // Measurement failed + sgp30_counter++; + if (30 == sgp30_counter) { + sgp30_counter = 0; + + uint16_t TVOC_base; + uint16_t eCO2_base; + + if (!sgp.getIAQBaseline(&eCO2_base, &TVOC_base)) return; // Failed to get baseline readings +// snprintf_P(log_data, sizeof(log_data), PSTR("SGP: Baseline values eCO2 0x%04X, TVOC 0x%04X"), eCO2_base, TVOC_base); +// AddLog(LOG_LEVEL_DEBUG); + } + sgp30_ready = 1; + } +} + +const char HTTP_SNS_TVOC[] PROGMEM = "%s{s}SGP30 " D_TVOC "{m}%d " D_UNIT_PARTS_PER_BILLION "{e}"; + +void Sgp30Show(boolean json) +{ + if (sgp30_ready) { + if (json) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"SGP30\":{\"" D_JSON_CO2 "\":%d,\"" D_JSON_TVOC "\":%d}"), mqtt_data, sgp.eCO2, sgp.TVOC); +#ifdef USE_DOMOTICZ + DomoticzSensor(DZ_AIRQUALITY, sgp.eCO2); +#endif // USE_DOMOTICZ + } else { +#ifdef USE_WEBSERVER + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_CO2, mqtt_data, "SGP30", sgp.eCO2); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TVOC, mqtt_data, sgp.TVOC); +#endif + } + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +#define XSNS_21 + +boolean Xsns21(byte function) +{ + boolean result = false; + + if (i2c_flg) { + switch (function) { + case FUNC_EVERY_SECOND: + Sgp30Update(); + break; + case FUNC_JSON_APPEND: + Sgp30Show(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_APPEND: + Sgp30Show(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_SGP30 +#endif // USE_I2C \ No newline at end of file