diff --git a/I2CDEVICES.md b/I2CDEVICES.md index 5663af73ab67..650ffc540890 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -117,4 +117,4 @@ Index | Define | Driver | Device | Address(es) | Description 79 | USE_GDK101 | xsns_106 | GDK101 | 0x18 - 0x1B | Gamma Radiation Sensor 80 | USE_TC74 | xsns_108 | TC74 | 0x48 - 0x4F | Temperature sensor 81 | USE_PCA9557 | xdrv_69 | PCA95xx | 0x18 - 0x1F | 8-bit I/O expander as virtual button/switch/relay - 109 | USE_SGP41 | xsns_109 | SGP41 | 0x59 | Gas (TVOC/NOx index) + 82 | USE_SGP41 | xsns_109 | SGP41 | 0x59 | Gas (TVOC/NOx index) diff --git a/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp40.cpp b/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp40.cpp deleted file mode 100644 index f4ea08b15d32..000000000000 --- a/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp40.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* - * THIS FILE IS AUTOMATICALLY GENERATED - * - * I2C-Generator: 0.3.0 - * Yaml Version: 0.1.0 - * Template Version: 0.7.0-62-g3d691f9 - */ -/* - * Copyright (c) 2021, Sensirion AG - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of Sensirion AG 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 AND CONTRIBUTORS "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 OR CONTRIBUTORS 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. - */ - -#include "SensirionI2CSgp40.h" -#include "Arduino.h" -#include "SensirionCore.h" -#include - -#define SGP40_I2C_ADDRESS 0x59 - -SensirionI2CSgp40::SensirionI2CSgp40() { -} - -void SensirionI2CSgp40::begin(TwoWire& i2cBus) { - _i2cBus = &i2cBus; -} - -uint16_t SensirionI2CSgp40::measureRawSignal(uint16_t relativeHumidity, - uint16_t temperature, - uint16_t& srawVoc) { - uint16_t error; - uint8_t buffer[8]; - SensirionI2CTxFrame txFrame = - SensirionI2CTxFrame::createWithUInt16Command(0x260F, buffer, 8); - - error = txFrame.addUInt16(relativeHumidity); - error |= txFrame.addUInt16(temperature); - - if (error) { - return error; - } - - error = SensirionI2CCommunication::sendFrame(SGP40_I2C_ADDRESS, txFrame, - *_i2cBus); - if (error) { - return error; - } - - delay(30); - - SensirionI2CRxFrame rxFrame(buffer, 8); - error = SensirionI2CCommunication::receiveFrame(SGP40_I2C_ADDRESS, 3, - rxFrame, *_i2cBus); - if (error) { - return error; - } - - error |= rxFrame.getUInt16(srawVoc); - return error; -} - -uint16_t SensirionI2CSgp40::executeSelfTest(uint16_t& testResult) { - uint16_t error; - uint8_t buffer[3]; - SensirionI2CTxFrame txFrame = - SensirionI2CTxFrame::createWithUInt16Command(0x280E, buffer, 3); - - error = SensirionI2CCommunication::sendFrame(SGP40_I2C_ADDRESS, txFrame, - *_i2cBus); - if (error) { - return error; - } - - delay(320); - - SensirionI2CRxFrame rxFrame(buffer, 3); - error = SensirionI2CCommunication::receiveFrame(SGP40_I2C_ADDRESS, 3, - rxFrame, *_i2cBus); - if (error) { - return error; - } - - error |= rxFrame.getUInt16(testResult); - return error; -} - -uint16_t SensirionI2CSgp40::turnHeaterOff() { - uint16_t error; - uint8_t buffer[2]; - SensirionI2CTxFrame txFrame = - SensirionI2CTxFrame::createWithUInt16Command(0x3615, buffer, 2); - - error = SensirionI2CCommunication::sendFrame(SGP40_I2C_ADDRESS, txFrame, - *_i2cBus); - delay(1); - return error; -} - -uint16_t SensirionI2CSgp40::getSerialNumber(uint16_t serialNumber[], - uint8_t serialNumberSize) { - uint16_t error; - uint8_t buffer[9]; - SensirionI2CTxFrame txFrame = - SensirionI2CTxFrame::createWithUInt16Command(0x3682, buffer, 9); - - error = SensirionI2CCommunication::sendFrame(SGP40_I2C_ADDRESS, txFrame, - *_i2cBus); - if (error) { - return error; - } - - delay(1); - - SensirionI2CRxFrame rxFrame(buffer, 9); - error = SensirionI2CCommunication::receiveFrame(SGP40_I2C_ADDRESS, 9, - rxFrame, *_i2cBus); - if (error) { - return error; - } - - error |= rxFrame.getUInt16(serialNumber[0]); - error |= rxFrame.getUInt16(serialNumber[1]); - error |= rxFrame.getUInt16(serialNumber[2]); - return error; -} \ No newline at end of file diff --git a/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp40.h b/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp40.h deleted file mode 100644 index d4fbe2595c81..000000000000 --- a/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp40.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * THIS FILE IS AUTOMATICALLY GENERATED - * - * I2C-Generator: 0.3.0 - * Yaml Version: 0.1.0 - * Template Version: 0.7.0-62-g3d691f9 - */ -/* - * Copyright (c) 2021, Sensirion AG - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of Sensirion AG 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 AND CONTRIBUTORS "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 OR CONTRIBUTORS 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. - */ - -#ifndef SENSIRIONI2CSGP40_H -#define SENSIRIONI2CSGP40_H - -#include - -#include - -class SensirionI2CSgp40 { - - public: - SensirionI2CSgp40(); - /** - * begin() - Initializes the SensirionI2CSgp40 class. - * - * @param serial Arduino stream object to be communicated with. - * - */ - void begin(TwoWire& i2cBus); - - /** - * measureRawSignal() - This command starts/continues the VOC measurement - * mode - * - * @param relativeHumidity Leaves humidity compensation disabled by sending - * the default value 0x8000 (50%RH) or enables humidity compensation when - * sending the relative humidity in ticks (ticks = %RH * 65535 / 100) - * - * @param temperature Leaves humidity compensation disabled by sending the - * default value 0x6666 (25 degC) or enables humidity compensation when - * sending the temperature in ticks (ticks = (degC + 45) * 65535 / 175) - * - * @param srawVoc u16 unsigned integer directly provides the raw signal - * SRAW_VOC in ticks which is proportional to the logarithm of the - * resistance of the sensing element. - * - * @return 0 on success, an error code otherwise - */ - uint16_t measureRawSignal(uint16_t relativeHumidity, uint16_t temperature, - uint16_t& srawVoc); - - /** - * executeSelfTest() - This command triggers the built-in self-test checking - * for integrity of the hotplate and MOX material and returns the result of - * this test as 2 bytes - * - * @param testResult 0xD4 00: all tests passed successfully or 0x4B 00: one - * or more tests have failed - * - * @return 0 on success, an error code otherwise - */ - uint16_t executeSelfTest(uint16_t& testResult); - - /** - * turnHeaterOff() - This command turns the hotplate off and stops the - * measurement. Subsequently, the sensor enters the idle mode. - * - * @return 0 on success, an error code otherwise - */ - uint16_t turnHeaterOff(void); - - /** - * getSerialNumber() - This command provides the decimal serial number of - * the SGP40 chip by returning 3x2 bytes. - * - * @param serialNumber 48-bit unique serial number - * - * @return 0 on success, an error code otherwise - */ - uint16_t getSerialNumber(uint16_t serialNumber[], uint8_t serialNumberSize); - - private: - TwoWire* _i2cBus = nullptr; -}; - -#endif /* SENSIRIONI2CSGP40_H */ \ No newline at end of file diff --git a/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp41.cpp b/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp41.cpp index 8c7b8a77da4a..814704f365dc 100644 --- a/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp41.cpp +++ b/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp41.cpp @@ -1,12 +1,6 @@ -/* - * THIS FILE IS AUTOMATICALLY GENERATED - * - * I2C-Generator: 0.3.0 - * Yaml Version: 0.1.0 - * Template Version: 0.7.0-62-g3d691f9 - */ /* * Copyright (c) 2021, Sensirion AG + * Copyright (c) 2023, Andrew Klaus (Removing delay functions) * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -50,9 +44,8 @@ void SensirionI2CSgp41::begin(TwoWire& i2cBus) { _i2cBus = &i2cBus; } -uint16_t SensirionI2CSgp41::executeConditioning(uint16_t defaultRh, - uint16_t defaultT, - uint16_t& srawVoc) { +uint16_t SensirionI2CSgp41::sendConditioningCmd(uint16_t defaultRh, + uint16_t defaultT) { uint16_t error; uint8_t buffer[8]; SensirionI2CTxFrame txFrame = @@ -66,11 +59,13 @@ uint16_t SensirionI2CSgp41::executeConditioning(uint16_t defaultRh, error = SensirionI2CCommunication::sendFrame(SGP41_I2C_ADDRESS, txFrame, *_i2cBus); - if (error) { - return error; - } + return error; +} - delay(50); +uint16_t SensirionI2CSgp41::readConditioningValue(uint16_t& srawVoc){ + // This must run at least 50ms after initiateConditioning + uint16_t error; + uint8_t buffer[8]; SensirionI2CRxFrame rxFrame(buffer, 8); error = SensirionI2CCommunication::receiveFrame(SGP41_I2C_ADDRESS, 3, @@ -83,10 +78,8 @@ uint16_t SensirionI2CSgp41::executeConditioning(uint16_t defaultRh, return error; } -uint16_t SensirionI2CSgp41::measureRawSignals(uint16_t relativeHumidity, - uint16_t temperature, - uint16_t& srawVoc, - uint16_t& srawNox) { +uint16_t SensirionI2CSgp41::sendRawSignalsCmd(uint16_t relativeHumidity, + uint16_t temperature) { uint16_t error; uint8_t buffer[8]; SensirionI2CTxFrame txFrame = @@ -100,13 +93,16 @@ uint16_t SensirionI2CSgp41::measureRawSignals(uint16_t relativeHumidity, error = SensirionI2CCommunication::sendFrame(SGP41_I2C_ADDRESS, txFrame, *_i2cBus); - if (error) { - return error; - } + return error; +} - delay(50); +uint16_t SensirionI2CSgp41::readRawSignalsValue(uint16_t& srawVoc, + uint16_t& srawNox) { + // This must run 50ms after initiateRawSignals - SensirionI2CRxFrame rxFrame(buffer, 8); + uint16_t error; + uint8_t buffer[6]; + SensirionI2CRxFrame rxFrame(buffer, 6); error = SensirionI2CCommunication::receiveFrame(SGP41_I2C_ADDRESS, 6, rxFrame, *_i2cBus); if (error) { @@ -118,7 +114,7 @@ uint16_t SensirionI2CSgp41::measureRawSignals(uint16_t relativeHumidity, return error; } -uint16_t SensirionI2CSgp41::executeSelfTest(uint16_t& testResult) { +uint16_t SensirionI2CSgp41::sendSelfTestCmd() { uint16_t error; uint8_t buffer[3]; SensirionI2CTxFrame txFrame = @@ -126,11 +122,13 @@ uint16_t SensirionI2CSgp41::executeSelfTest(uint16_t& testResult) { error = SensirionI2CCommunication::sendFrame(SGP41_I2C_ADDRESS, txFrame, *_i2cBus); - if (error) { - return error; - } + return error; +} - delay(320); +uint16_t SensirionI2CSgp41::readSelfTestValue(uint16_t& testResult) { + // Must run 320ms after initiateSelfTest + uint16_t error; + uint8_t buffer[3]; SensirionI2CRxFrame rxFrame(buffer, 3); error = SensirionI2CCommunication::receiveFrame(SGP41_I2C_ADDRESS, 3, diff --git a/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp41.h b/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp41.h index 51cbaa7add59..9fdd72aab32a 100644 --- a/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp41.h +++ b/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp41.h @@ -72,8 +72,9 @@ class SensirionI2CSgp41 { * * @return 0 on success, an error code otherwise */ - uint16_t executeConditioning(uint16_t defaultRh, uint16_t defaultT, - uint16_t& srawVoc); + uint16_t sendConditioningCmd(uint16_t defaultRh, uint16_t defaultT); + + uint16_t readConditioningValue(uint16_t& srawVoc); /** * measureRawSignals() - This command starts/continues the VOC+NOx @@ -97,8 +98,8 @@ class SensirionI2CSgp41 { * * @return 0 on success, an error code otherwise */ - uint16_t measureRawSignals(uint16_t relativeHumidity, uint16_t temperature, - uint16_t& srawVoc, uint16_t& srawNox); + uint16_t sendRawSignalsCmd(uint16_t relativeHumidity, uint16_t temperature); + uint16_t readRawSignalsValue(uint16_t& srawVoc, uint16_t& srawNox); /** * executeSelfTest() - This command triggers the built-in self-test checking @@ -113,7 +114,8 @@ class SensirionI2CSgp41 { * * @return 0 on success, an error code otherwise */ - uint16_t executeSelfTest(uint16_t& testResult); + uint16_t sendSelfTestCmd(void); + uint16_t readSelfTestValue(uint16_t& testResult); /** * turnHeaterOff() - This command turns the hotplate off and stops the diff --git a/tasmota/tasmota_xsns_sensor/xsns_109_sgp41.ino b/tasmota/tasmota_xsns_sensor/xsns_109_sgp41.ino index 65cc8c5f556b..0ae10b5d96f8 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_109_sgp41.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_109_sgp41.ino @@ -22,7 +22,7 @@ /*********************************************************************************************\ * SGP41 - Gas (TVOC - Total Volatile Organic Compounds) and NOx * - * Source: Gerhard Mutz and Industries + * Source: Sensirion Driver, with mods by Andrew Klaus * Adaption for TASMOTA: Andrew Klaus * * I2C Address: 0x59 @@ -39,121 +39,185 @@ extern "C" { #include "sensirion_gas_index_algorithm.h" }; +enum SGP41_State { + STATE_SGP41_START, + STATE_SGP41_SELFTEST_SENT, + STATE_SGP41_SELFTEST_WAIT, + STATE_SGP41_SELFTEST_DONE, + STATE_SGP41_COND_SENT, + STATE_SGP41_COND_DONE, + STATE_SGP41_NORMAL, + STATE_SGP41_FAIL, +}; SensirionI2CSgp41 sgp41; +SGP41_State sgp41_state = STATE_SGP41_START; bool sgp41_init = false; -bool sgp41_ready = false; +bool sgp41_read_pend = false; + uint16_t srawVoc; uint16_t srawNox; int32_t voc_index_sgp41; int32_t nox_index_sgp41; -uint16_t conditioning_s = 1; +uint16_t conditioning_s = 10; // 10 second delay for startup GasIndexAlgorithmParams voc_algorithm_params; GasIndexAlgorithmParams nox_algorithm_params; /********************************************************************************************/ -void sgp41_print_serial(uint16_t serialNumber[], uint8_t serialNumberSize) { - Serial.print("SerialNumber:"); - Serial.print("0x"); - for (size_t i = 0; i < serialNumberSize; i++) { - uint16_t value = serialNumber[i]; - Serial.print(value < 4096 ? "0" : ""); - Serial.print(value < 256 ? "0" : ""); - Serial.print(value < 16 ? "0" : ""); - Serial.print(value, HEX); - } - Serial.println(); -} void sgp41_Init(void) { if (!I2cSetDevice(SGP41_ADDRESS)) { return; } - uint16_t testResult; uint8_t serialNumberSize = 3; uint16_t serialNumber[serialNumberSize]; uint16_t error; - char errorMessage[256]; sgp41.begin(Wire); error = sgp41.getSerialNumber(serialNumber, serialNumberSize); if (error) { - Serial.println("Failed to get s/n from sgp41 driver"); + Sgp41HandleError(error); return; + } else { + AddLog(LOG_LEVEL_INFO, PSTR("SGP41 serial nr 0x%X 0x%X 0x%X") ,serialNumber[0], serialNumber[1], serialNumber[2]); } - sgp41_init = true; I2cSetActiveFound(SGP41_ADDRESS, "SGP41"); - sgp41_print_serial(serialNumber, serialNumberSize); - error = sgp41.executeSelfTest(testResult); + sgp41_init = true; + error = sgp41.sendSelfTestCmd(); + if (error) { - Serial.print("Error trying to execute executeSelfTest(): "); - errorToString(error, errorMessage, 256); - Serial.println(errorMessage); - } else if (testResult != 0xD400) { - Serial.print("executeSelfTest failed with error: "); - Serial.println(testResult); + Sgp41HandleError(error); + sgp41_state = STATE_SGP41_FAIL; + return; } + sgp41_state = STATE_SGP41_SELFTEST_SENT; + GasIndexAlgorithm_init(&nox_algorithm_params, GasIndexAlgorithm_ALGORITHM_TYPE_NOX); GasIndexAlgorithm_init(&voc_algorithm_params, GasIndexAlgorithm_ALGORITHM_TYPE_VOC); } -void Sgp41Update(void) +void Sgp41HandleError(uint16_t error) { + char errorMessage[256]; + errorToString(error, errorMessage, 256); + AddLog(LOG_LEVEL_ERROR, PSTR("SGP41 error: %s"), errorMessage); +} + +void Sgp41SendReadCmd(void) { - sgp41_ready = true; + // Check if we're already waiting for a read + // Or if we need to wait a cycle before initiating a reading + if (sgp41_read_pend){return;} - char errorMessage[256]; - uint16_t defaultRh = 0x8000; - uint16_t defaultT = 0x6666; uint16_t error; + uint16_t rhticks = (uint16_t)((TasmotaGlobal.humidity * 65535) / 100 + 0.5); + uint16_t tempticks = (uint16_t)(((TasmotaGlobal.temperature_celsius + 45) * 65535) / 175); - if (!(TasmotaGlobal.uptime%10)) { - // store settings every 10 seconds - // Conversion from https://sensirion.com/media/documents/5FE8673C/61E96F50/Sensirion_Gas_Sensors_Datasheet_SGP41.pdf - uint16_t rhticks = (uint16_t)((TasmotaGlobal.humidity * 65535) / 100 + 0.5); - uint16_t tempticks = (uint16_t)(((TasmotaGlobal.temperature_celsius + 45) * 65535) / 175); + // Handle self testing + // Wait 1 cycle (at least 320ms to read selftest value) + if (sgp41_state == STATE_SGP41_SELFTEST_SENT) { + sgp41_state = STATE_SGP41_SELFTEST_WAIT; + return; + } else if (sgp41_state == STATE_SGP41_SELFTEST_WAIT) { + if (Sgp41ReadSelfTest()){ + sgp41_state = STATE_SGP41_FAIL; + return; + } else { + sgp41_state = STATE_SGP41_SELFTEST_DONE; + } + } + // Initiate conditioning + if (sgp41_state == STATE_SGP41_SELFTEST_DONE) { + error = sgp41.sendConditioningCmd(0x8000, 0x6666); + sgp41_state = STATE_SGP41_COND_SENT; + + if (error) { + Sgp41HandleError(error); + } + return; + } + + if (sgp41_state == STATE_SGP41_COND_DONE) { + sgp41_state = STATE_SGP41_NORMAL; + } + + // Normal operation + if (sgp41_state == STATE_SGP41_NORMAL) { + error = sgp41.sendRawSignalsCmd(rhticks, tempticks); + if (error) { + Sgp41HandleError(error); + } else { + sgp41_read_pend = true; + } + return; + } + + return; +} + +bool Sgp41ReadSelfTest() { + uint16_t testResult; + uint16_t error; + + error = sgp41.readSelfTestValue(testResult); + if (error) { + Sgp41HandleError(error); + return true; + } else if (testResult != 0xD400) { + AddLog(LOG_LEVEL_ERROR, PSTR("SGP41: executeSelfTest failed with error: %s"), testResult); + return true; + } + + return false; +} + +void Sgp41Update(void) +{ + uint16_t error; + + // Conditioning - NOx needs 10s to warmup + if (sgp41_state == STATE_SGP41_COND_SENT) { if (conditioning_s > 0) { - // During NOx conditioning (10s) SRAW NOx will remain 0 - error = sgp41.executeConditioning(rhticks, tempticks, srawVoc); - GasIndexAlgorithm_process(&voc_algorithm_params, srawVoc, &voc_index_sgp41); - conditioning_s--; + conditioning_s--; + return; } else { - // Read Measurement - error = sgp41.measureRawSignals(rhticks, tempticks, srawVoc, srawNox); + sgp41_state = STATE_SGP41_COND_DONE; + } + } - if (error) { - Serial.print("Error trying to execute measureRawSignals(): "); - errorToString(error, errorMessage, 256); - Serial.println(errorMessage); - } + if (sgp41_state == STATE_SGP41_NORMAL && sgp41_read_pend) { + error = sgp41.readRawSignalsValue(srawVoc, srawNox); + sgp41_read_pend = false; + if (!error) { GasIndexAlgorithm_process(&voc_algorithm_params, srawVoc, &voc_index_sgp41); GasIndexAlgorithm_process(&nox_algorithm_params, srawNox, &nox_index_sgp41); + } else { + Sgp41HandleError(error); } - } } #ifdef USE_WEBSERVER const char HTTP_SNS_SGP41[] PROGMEM = "{s}SGP41 TVOC " D_JSON_RAW "{m}%d " "{e}" // {s} = , {m} = , {e} = - "{s}SGP41 NOx " D_JSON_RAW "{m}%d " "{e}" + "{s}SGP41 NOX " D_JSON_RAW "{m}%d " "{e}" "{s}SGP41 " D_TVOC "{m}%d " "{e}" "{s}SGP41 " D_NOX "{m}%d " "{e}"; #endif void Sgp41Show(bool json) { - if (sgp41_ready) { + if (sgp41_state == STATE_SGP41_NORMAL) { if (json) { - ResponseAppend_P(PSTR(",\"SGP41\":{\"" D_JSON_RAW "\":%d,\"" D_JSON_AIRQUALITY "\":%d"), srawVoc, voc_index_sgp41); + ResponseAppend_P(PSTR(",\"SGP41\":{\"VOC_" D_JSON_RAW "\":%d,\"NOX_" D_JSON_RAW "\":%d,\"" D_TVOC "\":%d,\"" D_NOX "\":%d"), srawVoc, srawNox, voc_index_sgp41, nox_index_sgp41); ResponseJsonEnd(); #ifdef USE_DOMOTICZ if (0 == TasmotaGlobal.tele_period) DomoticzSensor(DZ_AIRQUALITY, srawVoc); @@ -181,6 +245,9 @@ bool Xsns109(uint32_t function) } else if (sgp41_init) { switch (function) { + case FUNC_EVERY_250_MSECOND: + Sgp41SendReadCmd(); + break; case FUNC_EVERY_SECOND: Sgp41Update(); break;