├── images ├── SEN5x.png └── SEN5X_pinout.png ├── .github └── workflows │ ├── github_release.yml │ └── arduino_quality_check.yml ├── library.properties ├── .clang-format ├── CHANGELOG.md ├── LICENSE ├── keywords.txt ├── .gitignore ├── README.md ├── examples └── exampleUsage │ └── exampleUsage.ino └── src ├── SensirionI2CSen5x.cpp └── SensirionI2CSen5x.h /images/SEN5x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensirion/arduino-i2c-sen5x/HEAD/images/SEN5x.png -------------------------------------------------------------------------------- /images/SEN5X_pinout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensirion/arduino-i2c-sen5x/HEAD/images/SEN5X_pinout.png -------------------------------------------------------------------------------- /.github/workflows/github_release.yml: -------------------------------------------------------------------------------- 1 | name: Github Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | github-release: 10 | uses: sensirion/.github/.github/workflows/driver.common.github_release.yml@main 11 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Sensirion I2C SEN5X 2 | version=0.3.0 3 | author=Sensirion 4 | maintainer=Sensirion 5 | sentence=Library for the SEN5X sensor family by Sensirion 6 | paragraph=Enables you to use the SEN50, SEN54 and SEN55 via I2C. 7 | url=https://github.com/Sensirion/arduino-i2c-sen5x 8 | category=Sensors 9 | depends=Sensirion Core 10 | includes=SensirionI2CSen5x.h 11 | -------------------------------------------------------------------------------- /.github/workflows/arduino_quality_check.yml: -------------------------------------------------------------------------------- 1 | name: Quality check 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | push: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | arduino-quality: 13 | uses: sensirion/.github/.github/workflows/driver.arduino.check.yml@main 14 | with: 15 | expect-arduino-examples: true 16 | lint-lib-manager-check: update 17 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: LLVM 4 | IndentWidth: 4 5 | AlignAfterOpenBracket: Align 6 | AllowShortBlocksOnASingleLine: false 7 | AllowShortCaseLabelsOnASingleLine: false 8 | AllowShortFunctionsOnASingleLine: false 9 | IndentCaseLabels: true 10 | SpacesBeforeTrailingComments: 2 11 | PointerAlignment: Left 12 | AlignEscapedNewlines: Left 13 | ForEachMacros: ['TEST_GROUP', 'TEST'] 14 | ... 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ## [0.3.0] - 2023-01-19 10 | 11 | Fix scaling of typicalParticleSize for readMeasuredPmValues 12 | Fix comments for readMeasuredPmValuesAsIntegers 13 | 14 | ## [0.2.0] - 2022-03-30 15 | 16 | Add support for SEN50 17 | 18 | ## [0.1.0] - 2022-01-05 19 | 20 | Initial release 21 | 22 | [0.3.0]: https://github.com/Sensirion/embedded-i2c-sen5x/compare/0.2.0...0.3.0 23 | [0.2.0]: https://github.com/Sensirion/embedded-i2c-sen5x/compare/0.1.0...0.2.0 24 | [0.1.0]: https://github.com/Sensirion/arduino-i2c-sen5x/releases/tag/0.1.0 25 | 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021, Sensirion AG 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | SensirionI2CSen5x KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | startMeasurement KEYWORD2 15 | startMeasurementWithoutPm KEYWORD2 16 | stopMeasurement KEYWORD2 17 | readDataReady KEYWORD2 18 | readMeasuredValues KEYWORD2 19 | readMeasuredValuesAsIntegers KEYWORD2 20 | readMeasuredValuesSen50 KEYWORD2 21 | readMeasuredRawValues KEYWORD2 22 | readMeasuredPmValues KEYWORD2 23 | readMeasuredPmValuesAsIntegers KEYWORD2 24 | startFanCleaning KEYWORD2 25 | setTemperatureOffsetSimple KEYWORD2 26 | getTemperatureOffsetSimple KEYWORD2 27 | setTemperatureOffsetParameters KEYWORD2 28 | getTemperatureOffsetParameters KEYWORD2 29 | setWarmStartParameter KEYWORD2 30 | getWarmStartParameter KEYWORD2 31 | setVocAlgorithmTuningParameters KEYWORD2 32 | getVocAlgorithmTuningParameters KEYWORD2 33 | setNoxAlgorithmTuningParameters KEYWORD2 34 | getNoxAlgorithmTuningParameters KEYWORD2 35 | setRhtAccelerationMode KEYWORD2 36 | getRhtAccelerationMode KEYWORD2 37 | setVocAlgorithmState KEYWORD2 38 | getVocAlgorithmState KEYWORD2 39 | setFanAutoCleaningInterval KEYWORD2 40 | getFanAutoCleaningInterval KEYWORD2 41 | getProductName KEYWORD2 42 | getSerialNumber KEYWORD2 43 | getVersion KEYWORD2 44 | readDeviceStatus KEYWORD2 45 | readAndClearDeviceStatus KEYWORD2 46 | deviceReset KEYWORD2 47 | ####################################### 48 | # Instances (KEYWORD2) 49 | ####################################### 50 | 51 | sen5x KEYWORD2 52 | 53 | ####################################### 54 | # Constants (LITERAL1) 55 | ####################################### 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | app/bin/ 2 | app/pde.jar 3 | build/macosx/work/ 4 | arduino-core/bin/ 5 | arduino-core/arduino-core.jar 6 | hardware/arduino/bootloaders/caterina_LUFA/Descriptors.o 7 | hardware/arduino/bootloaders/caterina_LUFA/Descriptors.lst 8 | hardware/arduino/bootloaders/caterina_LUFA/Caterina.sym 9 | hardware/arduino/bootloaders/caterina_LUFA/Caterina.o 10 | hardware/arduino/bootloaders/caterina_LUFA/Caterina.map 11 | hardware/arduino/bootloaders/caterina_LUFA/Caterina.lst 12 | hardware/arduino/bootloaders/caterina_LUFA/Caterina.lss 13 | hardware/arduino/bootloaders/caterina_LUFA/Caterina.elf 14 | hardware/arduino/bootloaders/caterina_LUFA/Caterina.eep 15 | hardware/arduino/bootloaders/caterina_LUFA/.dep/ 16 | build/*.zip 17 | build/*.tar.bz2 18 | build/windows/work/ 19 | build/windows/*.zip 20 | build/windows/*.tgz 21 | build/windows/*.tar.bz2 22 | build/windows/libastylej* 23 | build/windows/liblistSerials* 24 | build/windows/arduino-*.zip 25 | build/windows/dist/*.tar.gz 26 | build/windows/dist/*.tar.bz2 27 | build/windows/launch4j-*.tgz 28 | build/windows/launch4j-*.zip 29 | build/windows/launcher/launch4j 30 | build/windows/WinAVR-*.zip 31 | build/macosx/arduino-*.zip 32 | build/macosx/dist/*.tar.gz 33 | build/macosx/dist/*.tar.bz2 34 | build/macosx/*.tar.bz2 35 | build/macosx/libastylej* 36 | build/macosx/appbundler*.jar 37 | build/macosx/appbundler*.zip 38 | build/macosx/appbundler 39 | build/macosx/appbundler-1.0ea-arduino? 40 | build/macosx/appbundler-1.0ea-arduino*.zip 41 | build/macosx/appbundler-1.0ea-upstream*.zip 42 | build/linux/work/ 43 | build/linux/dist/*.tar.gz 44 | build/linux/dist/*.tar.bz2 45 | build/linux/*.tgz 46 | build/linux/*.tar.xz 47 | build/linux/*.tar.bz2 48 | build/linux/*.zip 49 | build/linux/libastylej* 50 | build/linux/liblistSerials* 51 | build/shared/arduino-examples* 52 | build/shared/reference*.zip 53 | build/shared/Edison*.zip 54 | build/shared/Galileo*.zip 55 | build/shared/WiFi101-Updater-ArduinoIDE-Plugin*.zip 56 | test-bin 57 | *.iml 58 | .idea 59 | .DS_Store 60 | .directory 61 | hardware/arduino/avr/libraries/Bridge/examples/XivelyClient/passwords.h 62 | avr-toolchain-*.zip 63 | /app/nbproject/private/ 64 | /arduino-core/nbproject/private/ 65 | /app/build/ 66 | /arduino-core/build/ 67 | 68 | manifest.mf 69 | nbbuild.xml 70 | nbproject -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sensirion I2C SEN5X Arduino Library 2 | 3 | This is the Sensirion SEN5X library for Arduino using the 4 | modules I2C interface. 5 | 6 |
7 | 8 | ## Supported sensors 9 | 10 | - SEN50 (only particulate matter signals available) 11 | - SEN54 (no NOx signal available) 12 | - SEN55 (full feature set) 13 | 14 | # Installation 15 | 16 | To install, download the latest release as .zip file and add it to your 17 | [Arduino IDE](http://www.arduino.cc/en/main/software) via 18 | 19 | Sketch => Include Library => Add .ZIP Library... 20 | 21 | Don't forget to **install the dependencies** listed below the same way via `Add 22 | .ZIP Library` 23 | 24 | Note: Installation via the Arduino Library Manager is coming soon. 25 | 26 | # Dependencies 27 | 28 | * [Sensirion Core](https://github.com/Sensirion/arduino-core) 29 | 30 | 31 | # Quick Start 32 | 33 | 1. Connect the SEN5X Sensor to your Arduino board's standard 34 | I2C bus. Check the pinout of your Arduino board to find the correct pins. 35 | The pinout of the SEN5X Sensor board can be found in the 36 | data sheet. 37 | 38 | | *SEN5X* | *Arduino* | *Jumper Wire* | 39 | | ------- | ----------- | ------------- | 40 | | VCC | 5V | Red | 41 | | GND | GND | Black | 42 | | SDA | SDA | Green | 43 | | SCL | SCL | Yellow | 44 | | SEL | GND for I2C | Blue | 45 | 46 |
47 | 48 | | *Pin* | *Name* | *Description* | *Comments* | 49 | | ----- | ------ | ------------------------------- | -------------------------------- | 50 | | 1 | VCC | Supply Voltage | 5V ±10% | 51 | | 2 | GND | Ground | 52 | | 3 | SDA | I2C: Serial data input / output | TTL 5V and LVTTL 3.3V compatible | 53 | | 4 | SCL | I2C: Serial clock input | TTL 5V and LVTTL 3.3V compatible | 54 | | 5 | SEL | Interface select | Pull to GND to select I2C | 55 | | 6 | NC | Do not connect | 56 | 57 | 2. Open the `exampleUsage` sample project within the Arduino IDE 58 | 59 | File => Examples => Sensirion I2C SEN5X => exampleUsage 60 | 61 | 3. Click the `Upload` button in the Arduino IDE or 62 | 63 | Sketch => Upload 64 | 65 | 4. When the upload process has finished, open the `Serial Monitor` or `Serial 66 | Plotter` via the `Tools` menu to observe the measurement values. Note that 67 | the `Baud Rate` in the corresponding window has to be set to `115200 baud`. 68 | 69 | # Contributing 70 | 71 | **Contributions are welcome!** 72 | 73 | We develop and test this driver using our company internal tools (version 74 | control, continuous integration, code review etc.) and automatically 75 | synchronize the master branch with GitHub. But this doesn't mean that we don't 76 | respond to issues or don't accept pull requests on GitHub. In fact, you're very 77 | welcome to open issues or create pull requests :) 78 | 79 | This Sensirion library uses 80 | [`clang-format`](https://releases.llvm.org/download.html) to standardize the 81 | formatting of all our `.cpp` and `.h` files. Make sure your contributions are 82 | formatted accordingly: 83 | 84 | The `-i` flag will apply the format changes to the files listed. 85 | 86 | ```bash 87 | clang-format -i src/*.cpp src/*.h 88 | ``` 89 | 90 | Note that differences from this formatting will result in a failed build until 91 | they are fixed. 92 | 93 | # License 94 | 95 | See [LICENSE](LICENSE). 96 | -------------------------------------------------------------------------------- /examples/exampleUsage/exampleUsage.ino: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * I2C-Generator: 0.3.0 4 | * Yaml Version: 2.1.3 5 | * Template Version: 0.7.0-112-g190ecaa 6 | */ 7 | /* 8 | * Copyright (c) 2021, Sensirion AG 9 | * All rights reserved. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions are met: 13 | * 14 | * * Redistributions of source code must retain the above copyright notice, this 15 | * list of conditions and the following disclaimer. 16 | * 17 | * * Redistributions in binary form must reproduce the above copyright notice, 18 | * this list of conditions and the following disclaimer in the documentation 19 | * and/or other materials provided with the distribution. 20 | * 21 | * * Neither the name of Sensirion AG nor the names of its 22 | * contributors may be used to endorse or promote products derived from 23 | * this software without specific prior written permission. 24 | * 25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | * POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | // The used commands use up to 48 bytes. On some Arduino's the default buffer 43 | // space is not large enough 44 | #define MAXBUF_REQUIREMENT 48 45 | 46 | #if (defined(I2C_BUFFER_LENGTH) && \ 47 | (I2C_BUFFER_LENGTH >= MAXBUF_REQUIREMENT)) || \ 48 | (defined(BUFFER_LENGTH) && BUFFER_LENGTH >= MAXBUF_REQUIREMENT) 49 | #define USE_PRODUCT_INFO 50 | #endif 51 | 52 | SensirionI2CSen5x sen5x; 53 | 54 | void printModuleVersions() { 55 | uint16_t error; 56 | char errorMessage[256]; 57 | 58 | unsigned char productName[32]; 59 | uint8_t productNameSize = 32; 60 | 61 | error = sen5x.getProductName(productName, productNameSize); 62 | 63 | if (error) { 64 | Serial.print("Error trying to execute getProductName(): "); 65 | errorToString(error, errorMessage, 256); 66 | Serial.println(errorMessage); 67 | } else { 68 | Serial.print("ProductName:"); 69 | Serial.println((char*)productName); 70 | } 71 | 72 | uint8_t firmwareMajor; 73 | uint8_t firmwareMinor; 74 | bool firmwareDebug; 75 | uint8_t hardwareMajor; 76 | uint8_t hardwareMinor; 77 | uint8_t protocolMajor; 78 | uint8_t protocolMinor; 79 | 80 | error = sen5x.getVersion(firmwareMajor, firmwareMinor, firmwareDebug, 81 | hardwareMajor, hardwareMinor, protocolMajor, 82 | protocolMinor); 83 | if (error) { 84 | Serial.print("Error trying to execute getVersion(): "); 85 | errorToString(error, errorMessage, 256); 86 | Serial.println(errorMessage); 87 | } else { 88 | Serial.print("Firmware: "); 89 | Serial.print(firmwareMajor); 90 | Serial.print("."); 91 | Serial.print(firmwareMinor); 92 | Serial.print(", "); 93 | 94 | Serial.print("Hardware: "); 95 | Serial.print(hardwareMajor); 96 | Serial.print("."); 97 | Serial.println(hardwareMinor); 98 | } 99 | } 100 | 101 | void printSerialNumber() { 102 | uint16_t error; 103 | char errorMessage[256]; 104 | unsigned char serialNumber[32]; 105 | uint8_t serialNumberSize = 32; 106 | 107 | error = sen5x.getSerialNumber(serialNumber, serialNumberSize); 108 | if (error) { 109 | Serial.print("Error trying to execute getSerialNumber(): "); 110 | errorToString(error, errorMessage, 256); 111 | Serial.println(errorMessage); 112 | } else { 113 | Serial.print("SerialNumber:"); 114 | Serial.println((char*)serialNumber); 115 | } 116 | } 117 | 118 | void setup() { 119 | 120 | Serial.begin(115200); 121 | while (!Serial) { 122 | delay(100); 123 | } 124 | 125 | Wire.begin(); 126 | 127 | sen5x.begin(Wire); 128 | 129 | uint16_t error; 130 | char errorMessage[256]; 131 | error = sen5x.deviceReset(); 132 | if (error) { 133 | Serial.print("Error trying to execute deviceReset(): "); 134 | errorToString(error, errorMessage, 256); 135 | Serial.println(errorMessage); 136 | } 137 | 138 | // Print SEN55 module information if i2c buffers are large enough 139 | #ifdef USE_PRODUCT_INFO 140 | printSerialNumber(); 141 | printModuleVersions(); 142 | #endif 143 | 144 | // set a temperature offset in degrees celsius 145 | // Note: supported by SEN54 and SEN55 sensors 146 | // By default, the temperature and humidity outputs from the sensor 147 | // are compensated for the modules self-heating. If the module is 148 | // designed into a device, the temperature compensation might need 149 | // to be adapted to incorporate the change in thermal coupling and 150 | // self-heating of other device components. 151 | // 152 | // A guide to achieve optimal performance, including references 153 | // to mechanical design-in examples can be found in the app note 154 | // “SEN5x – Temperature Compensation Instruction” at www.sensirion.com. 155 | // Please refer to those application notes for further information 156 | // on the advanced compensation settings used 157 | // in `setTemperatureOffsetParameters`, `setWarmStartParameter` and 158 | // `setRhtAccelerationMode`. 159 | // 160 | // Adjust tempOffset to account for additional temperature offsets 161 | // exceeding the SEN module's self heating. 162 | float tempOffset = 0.0; 163 | error = sen5x.setTemperatureOffsetSimple(tempOffset); 164 | if (error) { 165 | Serial.print("Error trying to execute setTemperatureOffsetSimple(): "); 166 | errorToString(error, errorMessage, 256); 167 | Serial.println(errorMessage); 168 | } else { 169 | Serial.print("Temperature Offset set to "); 170 | Serial.print(tempOffset); 171 | Serial.println(" deg. Celsius (SEN54/SEN55 only"); 172 | } 173 | 174 | // Start Measurement 175 | error = sen5x.startMeasurement(); 176 | if (error) { 177 | Serial.print("Error trying to execute startMeasurement(): "); 178 | errorToString(error, errorMessage, 256); 179 | Serial.println(errorMessage); 180 | } 181 | } 182 | 183 | void loop() { 184 | uint16_t error; 185 | char errorMessage[256]; 186 | 187 | delay(1000); 188 | 189 | // Read Measurement 190 | float massConcentrationPm1p0; 191 | float massConcentrationPm2p5; 192 | float massConcentrationPm4p0; 193 | float massConcentrationPm10p0; 194 | float ambientHumidity; 195 | float ambientTemperature; 196 | float vocIndex; 197 | float noxIndex; 198 | 199 | error = sen5x.readMeasuredValues( 200 | massConcentrationPm1p0, massConcentrationPm2p5, massConcentrationPm4p0, 201 | massConcentrationPm10p0, ambientHumidity, ambientTemperature, vocIndex, 202 | noxIndex); 203 | 204 | if (error) { 205 | Serial.print("Error trying to execute readMeasuredValues(): "); 206 | errorToString(error, errorMessage, 256); 207 | Serial.println(errorMessage); 208 | } else { 209 | Serial.print("MassConcentrationPm1p0:"); 210 | Serial.print(massConcentrationPm1p0); 211 | Serial.print("\t"); 212 | Serial.print("MassConcentrationPm2p5:"); 213 | Serial.print(massConcentrationPm2p5); 214 | Serial.print("\t"); 215 | Serial.print("MassConcentrationPm4p0:"); 216 | Serial.print(massConcentrationPm4p0); 217 | Serial.print("\t"); 218 | Serial.print("MassConcentrationPm10p0:"); 219 | Serial.print(massConcentrationPm10p0); 220 | Serial.print("\t"); 221 | Serial.print("AmbientHumidity:"); 222 | if (isnan(ambientHumidity)) { 223 | Serial.print("n/a"); 224 | } else { 225 | Serial.print(ambientHumidity); 226 | } 227 | Serial.print("\t"); 228 | Serial.print("AmbientTemperature:"); 229 | if (isnan(ambientTemperature)) { 230 | Serial.print("n/a"); 231 | } else { 232 | Serial.print(ambientTemperature); 233 | } 234 | Serial.print("\t"); 235 | Serial.print("VocIndex:"); 236 | if (isnan(vocIndex)) { 237 | Serial.print("n/a"); 238 | } else { 239 | Serial.print(vocIndex); 240 | } 241 | Serial.print("\t"); 242 | Serial.print("NoxIndex:"); 243 | if (isnan(noxIndex)) { 244 | Serial.println("n/a"); 245 | } else { 246 | Serial.println(noxIndex); 247 | } 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /src/SensirionI2CSen5x.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * THIS FILE IS AUTOMATICALLY GENERATED 3 | * 4 | * I2C-Generator: 0.3.0 5 | * Yaml Version: 2.1.3 6 | * Template Version: 0.7.0-112-g190ecaa 7 | */ 8 | /* 9 | * Copyright (c) 2021, Sensirion AG 10 | * All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted provided that the following conditions are met: 14 | * 15 | * * Redistributions of source code must retain the above copyright notice, this 16 | * list of conditions and the following disclaimer. 17 | * 18 | * * Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * 22 | * * Neither the name of Sensirion AG nor the names of its 23 | * contributors may be used to endorse or promote products derived from 24 | * this software without specific prior written permission. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 30 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 | * POSSIBILITY OF SUCH DAMAGE. 37 | */ 38 | 39 | #include "SensirionI2CSen5x.h" 40 | #include "Arduino.h" 41 | #include "SensirionCore.h" 42 | #include 43 | #include 44 | 45 | #define SEN5X_I2C_ADDRESS 0x69 46 | #define UINT_INVALID 0xFFFF 47 | #define INT_INVALID 0x7FFF 48 | 49 | SensirionI2CSen5x::SensirionI2CSen5x() { 50 | } 51 | 52 | void SensirionI2CSen5x::begin(TwoWire& i2cBus) { 53 | _i2cBus = &i2cBus; 54 | } 55 | 56 | uint16_t SensirionI2CSen5x::startMeasurement() { 57 | uint16_t error = 0; 58 | uint8_t buffer[2]; 59 | SensirionI2CTxFrame txFrame = 60 | SensirionI2CTxFrame::createWithUInt16Command(0x21, buffer, 2); 61 | 62 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 63 | *_i2cBus); 64 | delay(50); 65 | return error; 66 | } 67 | 68 | uint16_t SensirionI2CSen5x::startMeasurementWithoutPm() { 69 | uint16_t error = 0; 70 | uint8_t buffer[2]; 71 | SensirionI2CTxFrame txFrame = 72 | SensirionI2CTxFrame::createWithUInt16Command(0x37, buffer, 2); 73 | 74 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 75 | *_i2cBus); 76 | delay(50); 77 | return error; 78 | } 79 | 80 | uint16_t SensirionI2CSen5x::stopMeasurement() { 81 | uint16_t error = 0; 82 | uint8_t buffer[2]; 83 | SensirionI2CTxFrame txFrame = 84 | SensirionI2CTxFrame::createWithUInt16Command(0x104, buffer, 2); 85 | 86 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 87 | *_i2cBus); 88 | delay(200); 89 | return error; 90 | } 91 | 92 | uint16_t SensirionI2CSen5x::readDataReady(bool& dataReady) { 93 | uint16_t error = 0; 94 | uint8_t buffer[3]; 95 | SensirionI2CTxFrame txFrame = 96 | SensirionI2CTxFrame::createWithUInt16Command(0x202, buffer, 3); 97 | 98 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 99 | *_i2cBus); 100 | if (error) { 101 | return error; 102 | } 103 | 104 | delay(20); 105 | 106 | SensirionI2CRxFrame rxFrame(buffer, 3); 107 | error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 3, 108 | rxFrame, *_i2cBus); 109 | if (error) { 110 | return error; 111 | } 112 | 113 | uint8_t padding; 114 | error |= rxFrame.getUInt8(padding); // remove padding 115 | error |= rxFrame.getBool(dataReady); 116 | return error; 117 | } 118 | 119 | uint16_t SensirionI2CSen5x::readMeasuredValues( 120 | float& massConcentrationPm1p0, float& massConcentrationPm2p5, 121 | float& massConcentrationPm4p0, float& massConcentrationPm10p0, 122 | float& ambientHumidity, float& ambientTemperature, float& vocIndex, 123 | float& noxIndex) { 124 | 125 | uint16_t error = 0; 126 | uint16_t massConcentrationPm1p0Int; 127 | uint16_t massConcentrationPm2p5Int; 128 | uint16_t massConcentrationPm4p0Int; 129 | uint16_t massConcentrationPm10p0Int; 130 | int16_t ambientHumidityInt; 131 | int16_t ambientTemperatureInt; 132 | int16_t vocIndexInt; 133 | int16_t noxIndexInt; 134 | 135 | error = readMeasuredValuesAsIntegers( 136 | massConcentrationPm1p0Int, massConcentrationPm2p5Int, 137 | massConcentrationPm4p0Int, massConcentrationPm10p0Int, 138 | ambientHumidityInt, ambientTemperatureInt, vocIndexInt, noxIndexInt); 139 | 140 | if (error) { 141 | return error; 142 | } 143 | 144 | massConcentrationPm1p0 = massConcentrationPm1p0Int == UINT_INVALID 145 | ? NAN 146 | : massConcentrationPm1p0Int / 10.0f; 147 | massConcentrationPm2p5 = massConcentrationPm2p5Int == UINT_INVALID 148 | ? NAN 149 | : massConcentrationPm2p5Int / 10.0f; 150 | massConcentrationPm4p0 = massConcentrationPm4p0Int == UINT_INVALID 151 | ? NAN 152 | : massConcentrationPm4p0Int / 10.0f; 153 | massConcentrationPm10p0 = massConcentrationPm10p0Int == UINT_INVALID 154 | ? NAN 155 | : massConcentrationPm10p0Int / 10.0f; 156 | ambientHumidity = 157 | ambientHumidityInt == INT_INVALID ? NAN : ambientHumidityInt / 100.0f; 158 | ambientTemperature = ambientTemperatureInt == INT_INVALID 159 | ? NAN 160 | : ambientTemperatureInt / 200.0f; 161 | vocIndex = vocIndexInt == INT_INVALID ? NAN : vocIndexInt / 10.0f; 162 | noxIndex = noxIndexInt == INT_INVALID ? NAN : noxIndexInt / 10.0f; 163 | 164 | return NoError; 165 | } 166 | 167 | uint16_t SensirionI2CSen5x::readMeasuredValuesAsIntegers( 168 | uint16_t& massConcentrationPm1p0, uint16_t& massConcentrationPm2p5, 169 | uint16_t& massConcentrationPm4p0, uint16_t& massConcentrationPm10p0, 170 | int16_t& ambientHumidity, int16_t& ambientTemperature, int16_t& vocIndex, 171 | int16_t& noxIndex) { 172 | uint16_t error = 0; 173 | uint8_t buffer[24]; 174 | SensirionI2CTxFrame txFrame = 175 | SensirionI2CTxFrame::createWithUInt16Command(0x3C4, buffer, 24); 176 | 177 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 178 | *_i2cBus); 179 | if (error) { 180 | return error; 181 | } 182 | 183 | delay(20); 184 | 185 | SensirionI2CRxFrame rxFrame(buffer, 24); 186 | error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 24, 187 | rxFrame, *_i2cBus); 188 | if (error) { 189 | return error; 190 | } 191 | 192 | error |= rxFrame.getUInt16(massConcentrationPm1p0); 193 | error |= rxFrame.getUInt16(massConcentrationPm2p5); 194 | error |= rxFrame.getUInt16(massConcentrationPm4p0); 195 | error |= rxFrame.getUInt16(massConcentrationPm10p0); 196 | error |= rxFrame.getInt16(ambientHumidity); 197 | error |= rxFrame.getInt16(ambientTemperature); 198 | error |= rxFrame.getInt16(vocIndex); 199 | error |= rxFrame.getInt16(noxIndex); 200 | return error; 201 | } 202 | 203 | uint16_t SensirionI2CSen5x::readMeasuredRawValues(int16_t& rawHumidity, 204 | int16_t& rawTemperature, 205 | uint16_t& rawVoc, 206 | uint16_t& rawNox) { 207 | uint16_t error = 0; 208 | uint8_t buffer[12]; 209 | SensirionI2CTxFrame txFrame = 210 | SensirionI2CTxFrame::createWithUInt16Command(0x3D2, buffer, 12); 211 | 212 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 213 | *_i2cBus); 214 | if (error) { 215 | return error; 216 | } 217 | 218 | delay(20); 219 | 220 | SensirionI2CRxFrame rxFrame(buffer, 12); 221 | error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 12, 222 | rxFrame, *_i2cBus); 223 | if (error) { 224 | return error; 225 | } 226 | 227 | error |= rxFrame.getInt16(rawHumidity); 228 | error |= rxFrame.getInt16(rawTemperature); 229 | error |= rxFrame.getUInt16(rawVoc); 230 | error |= rxFrame.getUInt16(rawNox); 231 | return error; 232 | } 233 | 234 | uint16_t SensirionI2CSen5x::readMeasuredValuesSen50( 235 | float& massConcentrationPm1p0, float& massConcentrationPm2p5, 236 | float& massConcentrationPm4p0, float& massConcentrationPm10p0) { 237 | 238 | uint16_t error = 0; 239 | float ambientHumidityDummy; 240 | float ambientTemperatureDummy; 241 | float vocIndexDummy; 242 | float noxIndexDummy; 243 | error = readMeasuredValues(massConcentrationPm1p0, massConcentrationPm2p5, 244 | massConcentrationPm4p0, massConcentrationPm10p0, 245 | ambientHumidityDummy, ambientTemperatureDummy, 246 | vocIndexDummy, noxIndexDummy); 247 | return error; 248 | } 249 | 250 | uint16_t SensirionI2CSen5x::readMeasuredPmValues( 251 | float& massConcentrationPm1p0, float& massConcentrationPm2p5, 252 | float& massConcentrationPm4p0, float& massConcentrationPm10p0, 253 | float& numberConcentrationPm0p5, float& numberConcentrationPm1p0, 254 | float& numberConcentrationPm2p5, float& numberConcentrationPm4p0, 255 | float& numberConcentrationPm10p0, float& typicalParticleSize) { 256 | 257 | uint16_t error = 0; 258 | uint16_t massConcentrationPm1p0Int; 259 | uint16_t massConcentrationPm2p5Int; 260 | uint16_t massConcentrationPm4p0Int; 261 | uint16_t massConcentrationPm10p0Int; 262 | uint16_t numberConcentrationPm0p5Int; 263 | uint16_t numberConcentrationPm1p0Int; 264 | uint16_t numberConcentrationPm2p5Int; 265 | uint16_t numberConcentrationPm4p0Int; 266 | uint16_t numberConcentrationPm10p0Int; 267 | uint16_t typicalParticleSizeInt; 268 | 269 | error = readMeasuredPmValuesAsIntegers( 270 | massConcentrationPm1p0Int, massConcentrationPm2p5Int, 271 | massConcentrationPm4p0Int, massConcentrationPm10p0Int, 272 | numberConcentrationPm0p5Int, numberConcentrationPm1p0Int, 273 | numberConcentrationPm2p5Int, numberConcentrationPm4p0Int, 274 | numberConcentrationPm10p0Int, typicalParticleSizeInt); 275 | 276 | if (error) { 277 | return error; 278 | } 279 | 280 | massConcentrationPm1p0 = massConcentrationPm1p0Int == UINT_INVALID 281 | ? NAN 282 | : massConcentrationPm1p0Int / 10.0f; 283 | massConcentrationPm2p5 = massConcentrationPm2p5Int == UINT_INVALID 284 | ? NAN 285 | : massConcentrationPm2p5Int / 10.0f; 286 | massConcentrationPm4p0 = massConcentrationPm4p0Int == UINT_INVALID 287 | ? NAN 288 | : massConcentrationPm4p0Int / 10.0f; 289 | massConcentrationPm10p0 = massConcentrationPm10p0Int == UINT_INVALID 290 | ? NAN 291 | : massConcentrationPm10p0Int / 10.0f; 292 | numberConcentrationPm0p5 = numberConcentrationPm0p5Int == UINT_INVALID 293 | ? NAN 294 | : numberConcentrationPm0p5Int / 10.0f; 295 | numberConcentrationPm1p0 = numberConcentrationPm1p0Int == UINT_INVALID 296 | ? NAN 297 | : numberConcentrationPm1p0Int / 10.0f; 298 | numberConcentrationPm2p5 = numberConcentrationPm2p5Int == UINT_INVALID 299 | ? NAN 300 | : numberConcentrationPm2p5Int / 10.0f; 301 | numberConcentrationPm4p0 = numberConcentrationPm4p0Int == UINT_INVALID 302 | ? NAN 303 | : numberConcentrationPm4p0Int / 10.0f; 304 | numberConcentrationPm10p0 = numberConcentrationPm10p0Int == UINT_INVALID 305 | ? NAN 306 | : numberConcentrationPm10p0Int / 10.0f; 307 | typicalParticleSize = typicalParticleSizeInt == UINT_INVALID 308 | ? NAN 309 | : typicalParticleSizeInt / 1000.0f; 310 | 311 | return NoError; 312 | } 313 | 314 | uint16_t SensirionI2CSen5x::readMeasuredPmValuesAsIntegers( 315 | uint16_t& massConcentrationPm1p0, uint16_t& massConcentrationPm2p5, 316 | uint16_t& massConcentrationPm4p0, uint16_t& massConcentrationPm10p0, 317 | uint16_t& numberConcentrationPm0p5, uint16_t& numberConcentrationPm1p0, 318 | uint16_t& numberConcentrationPm2p5, uint16_t& numberConcentrationPm4p0, 319 | uint16_t& numberConcentrationPm10p0, uint16_t& typicalParticleSize) { 320 | uint16_t error = 0; 321 | uint8_t buffer[30]; 322 | SensirionI2CTxFrame txFrame = 323 | SensirionI2CTxFrame::createWithUInt16Command(0x413, buffer, 30); 324 | 325 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 326 | *_i2cBus); 327 | if (error) { 328 | return error; 329 | } 330 | 331 | delay(20); 332 | 333 | SensirionI2CRxFrame rxFrame(buffer, 30); 334 | error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 30, 335 | rxFrame, *_i2cBus); 336 | if (error) { 337 | return error; 338 | } 339 | 340 | error |= rxFrame.getUInt16(massConcentrationPm1p0); 341 | error |= rxFrame.getUInt16(massConcentrationPm2p5); 342 | error |= rxFrame.getUInt16(massConcentrationPm4p0); 343 | error |= rxFrame.getUInt16(massConcentrationPm10p0); 344 | error |= rxFrame.getUInt16(numberConcentrationPm0p5); 345 | error |= rxFrame.getUInt16(numberConcentrationPm1p0); 346 | error |= rxFrame.getUInt16(numberConcentrationPm2p5); 347 | error |= rxFrame.getUInt16(numberConcentrationPm4p0); 348 | error |= rxFrame.getUInt16(numberConcentrationPm10p0); 349 | error |= rxFrame.getUInt16(typicalParticleSize); 350 | return error; 351 | } 352 | 353 | uint16_t SensirionI2CSen5x::startFanCleaning() { 354 | uint16_t error = 0; 355 | uint8_t buffer[2]; 356 | SensirionI2CTxFrame txFrame = 357 | SensirionI2CTxFrame::createWithUInt16Command(0x5607, buffer, 2); 358 | 359 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 360 | *_i2cBus); 361 | delay(20); 362 | return error; 363 | } 364 | 365 | uint16_t SensirionI2CSen5x::setTemperatureOffsetSimple(float tempOffset) { 366 | int16_t defaultSlope = 0; 367 | uint16_t defaultTimeConstant = 0; 368 | int16_t tempOffsetTicks = static_cast(tempOffset * 200); 369 | return setTemperatureOffsetParameters(tempOffsetTicks, defaultSlope, 370 | defaultTimeConstant); 371 | } 372 | 373 | uint16_t SensirionI2CSen5x::getTemperatureOffsetSimple(float& tempOffset) { 374 | int16_t tempOffsetTicks; 375 | int16_t slope; 376 | uint16_t timeConstant; 377 | uint16_t error = 0; 378 | 379 | error = 380 | getTemperatureOffsetParameters(tempOffsetTicks, slope, timeConstant); 381 | if (error) { 382 | return error; 383 | } 384 | 385 | tempOffset = static_cast(tempOffsetTicks) / 200.0f; 386 | 387 | return NoError; 388 | } 389 | 390 | uint16_t SensirionI2CSen5x::setTemperatureOffsetParameters( 391 | int16_t tempOffset, int16_t slope, uint16_t timeConstant) { 392 | uint16_t error = 0; 393 | uint8_t buffer[11]; 394 | SensirionI2CTxFrame txFrame = 395 | SensirionI2CTxFrame::createWithUInt16Command(0x60B2, buffer, 11); 396 | 397 | error |= txFrame.addInt16(tempOffset); 398 | error |= txFrame.addInt16(slope); 399 | error |= txFrame.addUInt16(timeConstant); 400 | 401 | if (error) { 402 | return error; 403 | } 404 | 405 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 406 | *_i2cBus); 407 | delay(20); 408 | return error; 409 | } 410 | 411 | uint16_t SensirionI2CSen5x::getTemperatureOffsetParameters( 412 | int16_t& tempOffset, int16_t& slope, uint16_t& timeConstant) { 413 | uint16_t error = 0; 414 | uint8_t buffer[9]; 415 | SensirionI2CTxFrame txFrame = 416 | SensirionI2CTxFrame::createWithUInt16Command(0x60B2, buffer, 9); 417 | 418 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 419 | *_i2cBus); 420 | if (error) { 421 | return error; 422 | } 423 | 424 | delay(20); 425 | 426 | SensirionI2CRxFrame rxFrame(buffer, 9); 427 | error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 9, 428 | rxFrame, *_i2cBus); 429 | if (error) { 430 | return error; 431 | } 432 | 433 | error |= rxFrame.getInt16(tempOffset); 434 | error |= rxFrame.getInt16(slope); 435 | error |= rxFrame.getUInt16(timeConstant); 436 | return error; 437 | } 438 | 439 | uint16_t SensirionI2CSen5x::setWarmStartParameter(uint16_t warmStart) { 440 | uint16_t error = 0; 441 | uint8_t buffer[5]; 442 | SensirionI2CTxFrame txFrame = 443 | SensirionI2CTxFrame::createWithUInt16Command(0x60C6, buffer, 5); 444 | 445 | error |= txFrame.addUInt16(warmStart); 446 | 447 | if (error) { 448 | return error; 449 | } 450 | 451 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 452 | *_i2cBus); 453 | delay(20); 454 | return error; 455 | } 456 | 457 | uint16_t SensirionI2CSen5x::getWarmStartParameter(uint16_t& warmStart) { 458 | uint16_t error = 0; 459 | uint8_t buffer[3]; 460 | SensirionI2CTxFrame txFrame = 461 | SensirionI2CTxFrame::createWithUInt16Command(0x60C6, buffer, 3); 462 | 463 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 464 | *_i2cBus); 465 | if (error) { 466 | return error; 467 | } 468 | 469 | delay(20); 470 | 471 | SensirionI2CRxFrame rxFrame(buffer, 3); 472 | error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 3, 473 | rxFrame, *_i2cBus); 474 | if (error) { 475 | return error; 476 | } 477 | 478 | error |= rxFrame.getUInt16(warmStart); 479 | return error; 480 | } 481 | 482 | uint16_t SensirionI2CSen5x::setVocAlgorithmTuningParameters( 483 | int16_t indexOffset, int16_t learningTimeOffsetHours, 484 | int16_t learningTimeGainHours, int16_t gatingMaxDurationMinutes, 485 | int16_t stdInitial, int16_t gainFactor) { 486 | uint16_t error = 0; 487 | uint8_t buffer[20]; 488 | SensirionI2CTxFrame txFrame = 489 | SensirionI2CTxFrame::createWithUInt16Command(0x60D0, buffer, 20); 490 | 491 | error |= txFrame.addInt16(indexOffset); 492 | error |= txFrame.addInt16(learningTimeOffsetHours); 493 | error |= txFrame.addInt16(learningTimeGainHours); 494 | error |= txFrame.addInt16(gatingMaxDurationMinutes); 495 | error |= txFrame.addInt16(stdInitial); 496 | error |= txFrame.addInt16(gainFactor); 497 | 498 | if (error) { 499 | return error; 500 | } 501 | 502 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 503 | *_i2cBus); 504 | delay(20); 505 | return error; 506 | } 507 | 508 | uint16_t SensirionI2CSen5x::getVocAlgorithmTuningParameters( 509 | int16_t& indexOffset, int16_t& learningTimeOffsetHours, 510 | int16_t& learningTimeGainHours, int16_t& gatingMaxDurationMinutes, 511 | int16_t& stdInitial, int16_t& gainFactor) { 512 | uint16_t error = 0; 513 | uint8_t buffer[18]; 514 | SensirionI2CTxFrame txFrame = 515 | SensirionI2CTxFrame::createWithUInt16Command(0x60D0, buffer, 18); 516 | 517 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 518 | *_i2cBus); 519 | if (error) { 520 | return error; 521 | } 522 | 523 | delay(20); 524 | 525 | SensirionI2CRxFrame rxFrame(buffer, 18); 526 | error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 18, 527 | rxFrame, *_i2cBus); 528 | if (error) { 529 | return error; 530 | } 531 | 532 | error |= rxFrame.getInt16(indexOffset); 533 | error |= rxFrame.getInt16(learningTimeOffsetHours); 534 | error |= rxFrame.getInt16(learningTimeGainHours); 535 | error |= rxFrame.getInt16(gatingMaxDurationMinutes); 536 | error |= rxFrame.getInt16(stdInitial); 537 | error |= rxFrame.getInt16(gainFactor); 538 | return error; 539 | } 540 | 541 | uint16_t SensirionI2CSen5x::setNoxAlgorithmTuningParameters( 542 | int16_t indexOffset, int16_t learningTimeOffsetHours, 543 | int16_t learningTimeGainHours, int16_t gatingMaxDurationMinutes, 544 | int16_t stdInitial, int16_t gainFactor) { 545 | uint16_t error = 0; 546 | uint8_t buffer[20]; 547 | SensirionI2CTxFrame txFrame = 548 | SensirionI2CTxFrame::createWithUInt16Command(0x60E1, buffer, 20); 549 | 550 | error |= txFrame.addInt16(indexOffset); 551 | error |= txFrame.addInt16(learningTimeOffsetHours); 552 | error |= txFrame.addInt16(learningTimeGainHours); 553 | error |= txFrame.addInt16(gatingMaxDurationMinutes); 554 | error |= txFrame.addInt16(stdInitial); 555 | error |= txFrame.addInt16(gainFactor); 556 | 557 | if (error) { 558 | return error; 559 | } 560 | 561 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 562 | *_i2cBus); 563 | delay(20); 564 | return error; 565 | } 566 | 567 | uint16_t SensirionI2CSen5x::getNoxAlgorithmTuningParameters( 568 | int16_t& indexOffset, int16_t& learningTimeOffsetHours, 569 | int16_t& learningTimeGainHours, int16_t& gatingMaxDurationMinutes, 570 | int16_t& stdInitial, int16_t& gainFactor) { 571 | uint16_t error = 0; 572 | uint8_t buffer[18]; 573 | SensirionI2CTxFrame txFrame = 574 | SensirionI2CTxFrame::createWithUInt16Command(0x60E1, buffer, 18); 575 | 576 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 577 | *_i2cBus); 578 | if (error) { 579 | return error; 580 | } 581 | 582 | delay(20); 583 | 584 | SensirionI2CRxFrame rxFrame(buffer, 18); 585 | error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 18, 586 | rxFrame, *_i2cBus); 587 | if (error) { 588 | return error; 589 | } 590 | 591 | error |= rxFrame.getInt16(indexOffset); 592 | error |= rxFrame.getInt16(learningTimeOffsetHours); 593 | error |= rxFrame.getInt16(learningTimeGainHours); 594 | error |= rxFrame.getInt16(gatingMaxDurationMinutes); 595 | error |= rxFrame.getInt16(stdInitial); 596 | error |= rxFrame.getInt16(gainFactor); 597 | return error; 598 | } 599 | 600 | uint16_t SensirionI2CSen5x::setRhtAccelerationMode(uint16_t mode) { 601 | uint16_t error = 0; 602 | uint8_t buffer[5]; 603 | SensirionI2CTxFrame txFrame = 604 | SensirionI2CTxFrame::createWithUInt16Command(0x60F7, buffer, 5); 605 | 606 | error |= txFrame.addUInt16(mode); 607 | 608 | if (error) { 609 | return error; 610 | } 611 | 612 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 613 | *_i2cBus); 614 | delay(20); 615 | return error; 616 | } 617 | 618 | uint16_t SensirionI2CSen5x::getRhtAccelerationMode(uint16_t& mode) { 619 | uint16_t error = 0; 620 | uint8_t buffer[3]; 621 | SensirionI2CTxFrame txFrame = 622 | SensirionI2CTxFrame::createWithUInt16Command(0x60F7, buffer, 3); 623 | 624 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 625 | *_i2cBus); 626 | if (error) { 627 | return error; 628 | } 629 | 630 | delay(20); 631 | 632 | SensirionI2CRxFrame rxFrame(buffer, 3); 633 | error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 3, 634 | rxFrame, *_i2cBus); 635 | if (error) { 636 | return error; 637 | } 638 | 639 | error |= rxFrame.getUInt16(mode); 640 | return error; 641 | } 642 | 643 | uint16_t SensirionI2CSen5x::setVocAlgorithmState(const uint8_t state[], 644 | uint8_t stateSize) { 645 | uint16_t error = 0; 646 | uint8_t buffer[14]; 647 | SensirionI2CTxFrame txFrame = 648 | SensirionI2CTxFrame::createWithUInt16Command(0x6181, buffer, 14); 649 | 650 | error |= txFrame.addBytes(state, stateSize); 651 | 652 | if (error) { 653 | return error; 654 | } 655 | 656 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 657 | *_i2cBus); 658 | delay(20); 659 | return error; 660 | } 661 | 662 | uint16_t SensirionI2CSen5x::getVocAlgorithmState(uint8_t state[], 663 | uint8_t stateSize) { 664 | uint16_t error = 0; 665 | uint8_t buffer[12]; 666 | SensirionI2CTxFrame txFrame = 667 | SensirionI2CTxFrame::createWithUInt16Command(0x6181, buffer, 12); 668 | 669 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 670 | *_i2cBus); 671 | if (error) { 672 | return error; 673 | } 674 | 675 | delay(20); 676 | 677 | SensirionI2CRxFrame rxFrame(buffer, 12); 678 | error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 12, 679 | rxFrame, *_i2cBus); 680 | if (error) { 681 | return error; 682 | } 683 | 684 | error |= rxFrame.getBytes(state, stateSize); 685 | return error; 686 | } 687 | 688 | uint16_t SensirionI2CSen5x::setFanAutoCleaningInterval(uint32_t interval) { 689 | uint16_t error = 0; 690 | uint8_t buffer[8]; 691 | SensirionI2CTxFrame txFrame = 692 | SensirionI2CTxFrame::createWithUInt16Command(0x8004, buffer, 8); 693 | 694 | error |= txFrame.addUInt32(interval); 695 | 696 | if (error) { 697 | return error; 698 | } 699 | 700 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 701 | *_i2cBus); 702 | delay(20); 703 | return error; 704 | } 705 | 706 | uint16_t SensirionI2CSen5x::getFanAutoCleaningInterval(uint32_t& interval) { 707 | uint16_t error = 0; 708 | uint8_t buffer[6]; 709 | SensirionI2CTxFrame txFrame = 710 | SensirionI2CTxFrame::createWithUInt16Command(0x8004, buffer, 6); 711 | 712 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 713 | *_i2cBus); 714 | if (error) { 715 | return error; 716 | } 717 | 718 | delay(20); 719 | 720 | SensirionI2CRxFrame rxFrame(buffer, 6); 721 | error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 6, 722 | rxFrame, *_i2cBus); 723 | if (error) { 724 | return error; 725 | } 726 | 727 | error |= rxFrame.getUInt32(interval); 728 | return error; 729 | } 730 | 731 | uint16_t SensirionI2CSen5x::getProductName(unsigned char productName[], 732 | uint8_t productNameSize) { 733 | uint16_t error = 0; 734 | uint8_t buffer[48]; 735 | SensirionI2CTxFrame txFrame = 736 | SensirionI2CTxFrame::createWithUInt16Command(0xD014, buffer, 48); 737 | 738 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 739 | *_i2cBus); 740 | if (error) { 741 | return error; 742 | } 743 | 744 | delay(50); 745 | 746 | SensirionI2CRxFrame rxFrame(buffer, 48); 747 | error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 48, 748 | rxFrame, *_i2cBus); 749 | if (error) { 750 | return error; 751 | } 752 | 753 | error |= rxFrame.getBytes(productName, productNameSize); 754 | return error; 755 | } 756 | 757 | uint16_t SensirionI2CSen5x::getSerialNumber(unsigned char serialNumber[], 758 | uint8_t serialNumberSize) { 759 | uint16_t error = 0; 760 | uint8_t buffer[48]; 761 | SensirionI2CTxFrame txFrame = 762 | SensirionI2CTxFrame::createWithUInt16Command(0xD033, buffer, 48); 763 | 764 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 765 | *_i2cBus); 766 | if (error) { 767 | return error; 768 | } 769 | 770 | delay(50); 771 | 772 | SensirionI2CRxFrame rxFrame(buffer, 48); 773 | error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 48, 774 | rxFrame, *_i2cBus); 775 | if (error) { 776 | return error; 777 | } 778 | 779 | error |= rxFrame.getBytes(serialNumber, serialNumberSize); 780 | return error; 781 | } 782 | 783 | uint16_t 784 | SensirionI2CSen5x::getVersion(uint8_t& firmwareMajor, uint8_t& firmwareMinor, 785 | bool& firmwareDebug, uint8_t& hardwareMajor, 786 | uint8_t& hardwareMinor, uint8_t& protocolMajor, 787 | uint8_t& protocolMinor) { 788 | uint16_t error = 0; 789 | uint8_t buffer[12]; 790 | SensirionI2CTxFrame txFrame = 791 | SensirionI2CTxFrame::createWithUInt16Command(0xD100, buffer, 12); 792 | 793 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 794 | *_i2cBus); 795 | if (error) { 796 | return error; 797 | } 798 | 799 | delay(20); 800 | 801 | SensirionI2CRxFrame rxFrame(buffer, 12); 802 | error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 12, 803 | rxFrame, *_i2cBus); 804 | if (error) { 805 | return error; 806 | } 807 | 808 | error |= rxFrame.getUInt8(firmwareMajor); 809 | error |= rxFrame.getUInt8(firmwareMinor); 810 | error |= rxFrame.getBool(firmwareDebug); 811 | error |= rxFrame.getUInt8(hardwareMajor); 812 | error |= rxFrame.getUInt8(hardwareMinor); 813 | error |= rxFrame.getUInt8(protocolMajor); 814 | error |= rxFrame.getUInt8(protocolMinor); 815 | uint8_t padding; 816 | error |= rxFrame.getUInt8(padding); // remove padding 817 | return error; 818 | } 819 | 820 | uint16_t SensirionI2CSen5x::readDeviceStatus(uint32_t& deviceStatus) { 821 | uint16_t error = 0; 822 | uint8_t buffer[6]; 823 | SensirionI2CTxFrame txFrame = 824 | SensirionI2CTxFrame::createWithUInt16Command(0xD206, buffer, 6); 825 | 826 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 827 | *_i2cBus); 828 | if (error) { 829 | return error; 830 | } 831 | 832 | delay(20); 833 | 834 | SensirionI2CRxFrame rxFrame(buffer, 6); 835 | error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 6, 836 | rxFrame, *_i2cBus); 837 | if (error) { 838 | return error; 839 | } 840 | 841 | error |= rxFrame.getUInt32(deviceStatus); 842 | return error; 843 | } 844 | 845 | uint16_t SensirionI2CSen5x::readAndClearDeviceStatus(uint32_t& deviceStatus) { 846 | uint16_t error = 0; 847 | uint8_t buffer[6]; 848 | SensirionI2CTxFrame txFrame = 849 | SensirionI2CTxFrame::createWithUInt16Command(0xD210, buffer, 6); 850 | 851 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 852 | *_i2cBus); 853 | if (error) { 854 | return error; 855 | } 856 | 857 | delay(20); 858 | 859 | SensirionI2CRxFrame rxFrame(buffer, 6); 860 | error = SensirionI2CCommunication::receiveFrame(SEN5X_I2C_ADDRESS, 6, 861 | rxFrame, *_i2cBus); 862 | if (error) { 863 | return error; 864 | } 865 | 866 | error |= rxFrame.getUInt32(deviceStatus); 867 | return error; 868 | } 869 | 870 | uint16_t SensirionI2CSen5x::deviceReset() { 871 | uint16_t error = 0; 872 | uint8_t buffer[2]; 873 | SensirionI2CTxFrame txFrame = 874 | SensirionI2CTxFrame::createWithUInt16Command(0xD304, buffer, 2); 875 | 876 | error = SensirionI2CCommunication::sendFrame(SEN5X_I2C_ADDRESS, txFrame, 877 | *_i2cBus); 878 | delay(200); 879 | return error; 880 | } 881 | -------------------------------------------------------------------------------- /src/SensirionI2CSen5x.h: -------------------------------------------------------------------------------- 1 | /* 2 | * THIS FILE IS AUTOMATICALLY GENERATED 3 | * 4 | * I2C-Generator: 0.3.0 5 | * Yaml Version: 2.1.3 6 | * Template Version: 0.7.0-112-g190ecaa 7 | */ 8 | /* 9 | * Copyright (c) 2021, Sensirion AG 10 | * All rights reserved. 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted provided that the following conditions are met: 14 | * 15 | * * Redistributions of source code must retain the above copyright notice, this 16 | * list of conditions and the following disclaimer. 17 | * 18 | * * Redistributions in binary form must reproduce the above copyright notice, 19 | * this list of conditions and the following disclaimer in the documentation 20 | * and/or other materials provided with the distribution. 21 | * 22 | * * Neither the name of Sensirion AG nor the names of its 23 | * contributors may be used to endorse or promote products derived from 24 | * this software without specific prior written permission. 25 | * 26 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 30 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 | * POSSIBILITY OF SUCH DAMAGE. 37 | */ 38 | 39 | #ifndef SENSIRIONI2CSEN5X_H 40 | #define SENSIRIONI2CSEN5X_H 41 | 42 | #include 43 | 44 | #include 45 | 46 | class SensirionI2CSen5x { 47 | 48 | public: 49 | SensirionI2CSen5x(); 50 | /** 51 | * begin() - Initializes the SensirionI2CSen5x class. 52 | * 53 | * @param i2cBus Arduino stream object to use for communication. 54 | * 55 | */ 56 | void begin(TwoWire& i2cBus); 57 | 58 | /** 59 | * startMeasurement() - Starts a continuous measurement. 60 | 61 | * After starting the measurement, it takes some time (~1s) until the first 62 | * measurement results are available. You could poll with the command 63 | * 0x0202 \"Read Data Ready\" to check when the results are ready to read. 64 | * 65 | * If the device is in measure mode without particulate matter (low-power) 66 | * and the firmware version is at least 2.0, this command enables PM 67 | * measurement without affecting the already running RH/T/VOC/NOx 68 | * measurements (except that the \"data ready\"-flag will be cleared). In 69 | * previous firmware versions, this command is supported only in idle mode. 70 | * 71 | * @return 0 on success, an error code otherwise 72 | */ 73 | uint16_t startMeasurement(void); 74 | 75 | /** 76 | * startMeasurementWithoutPm() - Starts a continuous measurement without PM. 77 | * Only humidity, temperature, VOC and NOx are available in this mode. Laser 78 | * and fan are switched off to keep power consumption low. 79 | * 80 | * After starting the measurement, it takes some time (~1s) until the first 81 | * measurement results are available. You could poll with the command 82 | * 0x0202 \"Read Data Ready\" to check when the results are ready to read. 83 | * 84 | * If the device is in measure mode with particulate matter (normal measure 85 | * mode) and the firmware version is at least 2.0, this command disables PM 86 | * measurement without affecting the already running RH/T/VOC/NOx 87 | * measurements (except that the \"data ready\"-flag will be cleared). In 88 | * previous firmware versions, this command is supported only in idle mode. 89 | * 90 | * Supported sensors: SEN54, SEN55 91 | * 92 | * @return 0 on success, an error code otherwise 93 | */ 94 | uint16_t startMeasurementWithoutPm(void); 95 | 96 | /** 97 | * stopMeasurement() - Stops the measurement and returns to idle mode. 98 | * 99 | * If the device is already in idle mode, this command has no effect. 100 | * 101 | * @return 0 on success, an error code otherwise 102 | */ 103 | uint16_t stopMeasurement(void); 104 | 105 | /** 106 | * readDataReady() - This command can be used to check if new measurement 107 | * results are ready to read. The data ready flag is automatically reset 108 | * after reading the measurement values with the 0x03.. \"Read Measured 109 | * Values\" commands. 110 | * 111 | * @note During fan (auto-)cleaning, no measurement data is available for 112 | * several seconds and thus this flag will not be set until cleaning has 113 | * finished. So please expect gaps of several seconds at any time if fan 114 | * auto-cleaning is enabled. 115 | * 116 | * @param padding Padding byte, always 0x00. 117 | * 118 | * @param dataReady True (0x01) if data is ready, False (0x00) if not. When 119 | * no measurement is running, False will be returned. 120 | * 121 | * @return 0 on success, an error code otherwise 122 | */ 123 | uint16_t readDataReady(bool& dataReady); 124 | 125 | /** 126 | * readMeasuredValues() - Returns the measured values. 127 | * 128 | * The command 0x0202 \"Read Data Ready\" can be used to check if new 129 | * data is available since the last read operation. If no new data is 130 | * available, the previous values will be returned again. If no data is 131 | * available at all (e.g. measurement not running for at least one 132 | * second), all values will be NAN. 133 | * 134 | * @param massConcentrationPm1p0 PM1.0 [µg/m³] 135 | * Note: If this value is unknown, NAN is returned.* 136 | * 137 | * @param massConcentrationPm2p5 PM2.5 [µg/m³] 138 | * Note: If this value is unknown, NAN is returned.* 139 | * 140 | * @param massConcentrationPm4p0 PM4.0 [µg/m³] 141 | * Note: If this value is unknown, NAN is returned.* 142 | * 143 | * @param massConcentrationPm10p0 PM10.0 [µg/m³] 144 | * Note: If this value is unknown, NAN is returned.* 145 | * 146 | * @param ambientHumidity RH [%] 147 | * Note: If this value is unknown, NAN is returned.* 148 | * 149 | * @param ambientTemperature T [°C] 150 | * Note: If this value is unknown, NAN is returned.* 151 | * 152 | * @param vocIndex VOC Index 153 | * Note: If this value is unknown, NAN is returned.* 154 | * 155 | * @param noxIndex NOx Index 156 | * Note: If this value is unknown, which is true for SEN54, 157 | * NAN is returned. During the first 10..11 seconds after 158 | * power-on or device reset, this value will be NAN as well.* 159 | * 160 | * @return 0 on success, an error code otherwise 161 | */ 162 | uint16_t readMeasuredValues(float& massConcentrationPm1p0, 163 | float& massConcentrationPm2p5, 164 | float& massConcentrationPm4p0, 165 | float& massConcentrationPm10p0, 166 | float& ambientHumidity, 167 | float& ambientTemperature, float& vocIndex, 168 | float& noxIndex); 169 | 170 | /** 171 | * readMeasuredValuesAsIntegers() - Returns the measured values 172 | * without scaling factors applied. 173 | * 174 | * The command 0x0202 \"Read Data Ready\" can be used to check if new 175 | * data is available since the last read operation. If no new data is 176 | * available, the previous values will be returned again. If no data is 177 | * available at all (e.g. measurement not running for at least one 178 | * second), all values will be at their upper limit (0xFFFF for `uint16`, 179 | * 0x7FFF for `int16`). 180 | * 181 | * @param massConcentrationPm1p0 Value is scaled with factor 10: 182 | * PM1.0 [µg/m³] = value / 10 183 | * Note: If this value is unknown, 0xFFFF is returned.* 184 | * 185 | * @param massConcentrationPm2p5 Value is scaled with factor 10: 186 | * PM2.5 [µg/m³] = value / 10 187 | * Note: If this value is unknown, 0xFFFF is returned.* 188 | * 189 | * @param massConcentrationPm4p0 Value is scaled with factor 10: 190 | * PM4.0 [µg/m³] = value / 10 191 | * Note: If this value is unknown, 0xFFFF is returned.* 192 | * 193 | * @param massConcentrationPm10p0 Value is scaled with factor 10: 194 | * PM10.0 [µg/m³] = value / 10 195 | * Note: If this value is unknown, 0xFFFF is returned.* 196 | * 197 | * @param ambientHumidity Value is scaled with factor 100: 198 | * RH [%] = value /100 199 | * Note: If this value is unknown, 0x7FFF is returned.* 200 | * 201 | * @param ambientTemperature Value is scaled with factor 200: 202 | * T [°C] = value / 200 203 | * Note: If this value is unknown, 0x7FFF is returned.* 204 | * 205 | * @param vocIndex Value is scaled with factor 10: VOC Index = value / 10 206 | * Note: If this value is unknown, 0x7FFF is returned.* 207 | * 208 | * @param noxIndex Value is scaled with factor 10: NOx Index = value / 10 209 | * Note: If this value is unknown, which is the case for SEN54, 210 | * 0x7FFF is returned. During the first 10..11 seconds after power-on 211 | * or device reset, this value will be 0x7FFF as well.* 212 | * 213 | * @return 0 on success, an error code otherwise 214 | */ 215 | uint16_t readMeasuredValuesAsIntegers(uint16_t& massConcentrationPm1p0, 216 | uint16_t& massConcentrationPm2p5, 217 | uint16_t& massConcentrationPm4p0, 218 | uint16_t& massConcentrationPm10p0, 219 | int16_t& ambientHumidity, 220 | int16_t& ambientTemperature, 221 | int16_t& vocIndex, int16_t& noxIndex); 222 | 223 | /** 224 | * readMeasuredRawValues() - Returns the measured raw values. 225 | * 226 | * The command 0x0202 \"Read Data Ready\" can be used to check if new 227 | * data is available since the last read operation. If no new data is 228 | * available, the previous values will be returned again. If no data 229 | * is available at all (e.g. measurement not running for at least one 230 | * second), all values will be at their upper limit (0xFFFF for `uint16`, 231 | * 0x7FFF for `int16`). 232 | * 233 | * Supported sensors: SEN54 (no NOx), SEN55 234 | * 235 | * @param rawHumidity Value is scaled with factor 100: RH [%] = value / 100 236 | * Note: If this value is unknown, 0x7FFF is returned.* 237 | * 238 | * @param rawTemperature Value is scaled with factor 200: 239 | * T [°C] = value / 200 240 | * Note: If this value is unknown, 0x7FFF is returned.* 241 | * 242 | * @param rawVoc Raw measured VOC ticks without scale factor. 243 | * Note: If this value is unknown, 0xFFFF is returned.* 244 | * 245 | * @param rawNox Raw measured NOx ticks without scale factor. 246 | * Note: If this value is unknown, which is the case for SEN54, 247 | * 0xFFFF is returned. During the first 10..11 seconds after power-on 248 | * or device reset, this value will be 0xFFFF as well.* 249 | * 250 | * @return 0 on success, an error code otherwise 251 | */ 252 | uint16_t readMeasuredRawValues(int16_t& rawHumidity, 253 | int16_t& rawTemperature, uint16_t& rawVoc, 254 | uint16_t& rawNox); 255 | 256 | /** 257 | * readMeasuredValuesSen50() - Returns the measured values for SEN50. 258 | * 259 | * The command 0x0202 \"Read Data Ready\" can be used to check if new 260 | * data is available since the last read operation. If no new data is 261 | * available, the previous values will be returned again. If no data is 262 | * available at all (e.g. measurement not running for at least one 263 | * second), all values will be NAN. 264 | * 265 | * @param massConcentrationPm1p0 PM1.0 [µg/m³] 266 | * Note: If this value is unknown, NAN is returned.* 267 | * 268 | * @param massConcentrationPm2p5 PM2.5 [µg/m³] 269 | * Note: If this value is unknown, NAN is returned.* 270 | * 271 | * @param massConcentrationPm4p0 PM4.0 [µg/m³] 272 | * Note: If this value is unknown, NAN is returned.* 273 | * 274 | * @param massConcentrationPm10p0 PM10.0 [µg/m³] 275 | * Note: If this value is unknown, NAN is returned.* 276 | * 277 | * @return 0 on success, an error code otherwise 278 | */ 279 | uint16_t readMeasuredValuesSen50(float& massConcentrationPm1p0, 280 | float& massConcentrationPm2p5, 281 | float& massConcentrationPm4p0, 282 | float& massConcentrationPm10p0); 283 | 284 | /** 285 | * readMeasuredPmValues() - Returns the measured particulate matter values. 286 | * 287 | * The command 0x0202 \"Read Data Ready\" can be used to check if new 288 | * data is available since the last read operation. If no new data is 289 | * available, the previous values will be returned again. If no data 290 | * is available at all (e.g. measurement not running for at least one 291 | * second), all values will be NAN. 292 | * 293 | * @param massConcentrationPm1p0 PM1.0 [µg/m³] 294 | * Note: If this value is unknown, NAN is returned.* 295 | * 296 | * @param massConcentrationPm2p5 PM2.5 [µg/m³] 297 | * Note: If this value is unknown, NAN is returned.* 298 | * 299 | * @param massConcentrationPm4p0 PM4.0 [µg/m³] 300 | * Note: If this value is unknown, NAN is returned.* 301 | * 302 | * @param massConcentrationPm10p0 PM10.0 [µg/m³] 303 | * Note: If this value is unknown, NAN is returned.* 304 | * 305 | * @param numberConcentrationPm0p5 PM0.5 [#/cm³] 306 | * Note: If this value is unknown, NAN is returned.* 307 | * 308 | * @param numberConcentrationPm1p0 PM1.0 [#/cm³] 309 | * Note: If this value is unknown, NAN is returned.* 310 | * 311 | * @param numberConcentrationPm2p5 PM2.5 [#/cm³] 312 | * Note: If this value is unknown, NAN is returned.* 313 | * 314 | * @param numberConcentrationPm4p0 PM4.0 [#/cm³] 315 | * Note: If this value is unknown, NAN is returned.* 316 | * 317 | * @param numberConcentrationPm10p0 PM10.0 [#/cm³] 318 | * Note: If this value is unknown, NAN is returned.* 319 | * 320 | * @param typicalParticleSize Size [µm] 321 | * Note: If this value is unknown, NAN is returned.* 322 | * 323 | * @return 0 on success, an error code otherwise 324 | */ 325 | uint16_t readMeasuredPmValues( 326 | float& massConcentrationPm1p0, float& massConcentrationPm2p5, 327 | float& massConcentrationPm4p0, float& massConcentrationPm10p0, 328 | float& numberConcentrationPm0p5, float& numberConcentrationPm1p0, 329 | float& numberConcentrationPm2p5, float& numberConcentrationPm4p0, 330 | float& numberConcentrationPm10p0, float& typicalParticleSize); 331 | 332 | /** 333 | * readMeasuredPmValuesAsIntegers() - Returns the measured particulate 334 | * matter values. 335 | * 336 | * The command 0x0202 \"Read Data Ready\" can be used to check if new 337 | * data is available since the last read operation. If no new data is 338 | * available, the previous values will be returned again. If no data 339 | * is available at all (e.g. measurement not running for at least one 340 | * second), all values will be 0xFFFF. 341 | * 342 | * @param massConcentrationPm1p0 Value is scaled with factor 10: 343 | * PM1.0 [µg/m³] = value / 10 344 | * Note: If this value is unknown, 0xFFFF is returned.* 345 | * 346 | * @param massConcentrationPm2p5 Value is scaled with factor 10: 347 | * PM2.5 [µg/m³] = value / 10 348 | * Note: If this value is unknown, 0xFFFF is returned.* 349 | * 350 | * @param massConcentrationPm4p0 Value is scaled with factor 10: 351 | * PM4.0 [µg/m³] = value / 10 352 | * Note: If this value is unknown, 0xFFFF is returned.* 353 | * 354 | * @param massConcentrationPm10p0 Value is scaled with factor 10: 355 | * PM10.0 [µg/m³] = value / 10 356 | * Note: If this value is unknown, 0xFFFF is returned.* 357 | * 358 | * @param numberConcentrationPm0p5 Value is scaled with factor 10: 359 | * PM0.5 [#/cm³] = value / 10 360 | * Note: If this value is unknown, 0xFFFF is returned.* 361 | * 362 | * @param numberConcentrationPm1p0 Value is scaled with factor 10: 363 | * PM1.0 [#/cm³] = value / 10 364 | * Note: If this value is unknown, 0xFFFF is returned.* 365 | * 366 | * @param numberConcentrationPm2p5 Value is scaled with factor 10: 367 | * PM2.5 [#/cm³] = value / 10 368 | * Note: If this value is unknown, 0xFFFF is returned.* 369 | * 370 | * @param numberConcentrationPm4p0 Value is scaled with factor 10: 371 | * PM4.0 [#/cm³] = value / 10 372 | * Note: If this value is unknown, 0xFFFF is returned.* 373 | * 374 | * @param numberConcentrationPm10p0 Value is scaled with factor 10: 375 | * PM10.0 [#/cm³] = value / 10 376 | * Note: If this value is unknown, 0xFFFF is returned.* 377 | * 378 | * @param typicalParticleSize Value is scaled with factor 1000: 379 | * Size [µm] = value / 1000 380 | * Note: If this value is unknown, 0xFFFF is returned.* 381 | * 382 | * @return 0 on success, an error code otherwise 383 | */ 384 | uint16_t readMeasuredPmValuesAsIntegers( 385 | uint16_t& massConcentrationPm1p0, uint16_t& massConcentrationPm2p5, 386 | uint16_t& massConcentrationPm4p0, uint16_t& massConcentrationPm10p0, 387 | uint16_t& numberConcentrationPm0p5, uint16_t& numberConcentrationPm1p0, 388 | uint16_t& numberConcentrationPm2p5, uint16_t& numberConcentrationPm4p0, 389 | uint16_t& numberConcentrationPm10p0, uint16_t& typicalParticleSize); 390 | 391 | /** 392 | * startFanCleaning() - Starts the fan cleaning manually. The \"data 393 | * ready\"-flag will be cleared immediately and during the next few seconds, 394 | * no new measurement results will be available (old values will be 395 | * returned). Once the cleaning is finished, the \"data ready\"-flag will be 396 | * set and new measurement results will be available. 397 | * 398 | * When executing this command while cleaning is already active, the 399 | * command does nothing. 400 | * 401 | * If you stop the measurement while fan cleaning is active, the cleaning 402 | * will be aborted immediately. 403 | * 404 | * @note This command is only available in measure mode with PM measurement 405 | * enabled, i.e. only if the fan is already running. In any other state, 406 | * this command does nothing. 407 | * 408 | * @return 0 on success, an error code otherwise 409 | */ 410 | uint16_t startFanCleaning(void); 411 | 412 | /** 413 | * setTemperatureOffsetSimple() - Sets the temperature offset parameter 414 | * in degrees celsius for the device, while leaving the other parameters at 415 | * their default setting. 416 | * 417 | * Supported sensors: SEN54, SEN55 418 | * 419 | * @param tempOffset Constant temperature offset in degrees celsius. 420 | * The default value is 0. 421 | * 422 | * @return 0 on success, an error code otherwise 423 | */ 424 | uint16_t setTemperatureOffsetSimple(float tempOffset); 425 | 426 | /** 427 | * getTemperatureOffsetSimple() - Gets the temperature offset parameter 428 | * in degrees celsius from the device. 429 | * @note The other parameters, such as slope and time constant may differ 430 | * from the default values, if they were previously set using 431 | * `setTemperatureOffsetParameters`. 432 | * 433 | * Supported sensors: SEN54, SEN55 434 | * 435 | * @param tempOffset Constant temperature offset in degrees celsius. 436 | * 437 | * @return 0 on success, an error code otherwise 438 | */ 439 | uint16_t getTemperatureOffsetSimple(float& tempOffset); 440 | 441 | /** 442 | * setTemperatureOffsetParameters() - Sets the temperature offset parameters 443 | * for the device. 444 | * 445 | * Supported sensors: SEN54, SEN55 446 | * 447 | * @param tempOffset Constant temperature offset scaled with factor 200 (T 448 | * [°C] = value / 200). The default value is 0. 449 | * 450 | * @param slope Normalized temperature offset slope scaled with factor 10000 451 | * (applied factor = value / 10000). The default value is 0. 452 | * 453 | * @param timeConstant Time constant [s] how fast the new slope and offset 454 | * will be applied. After the specified value in seconds, 63% of the new 455 | * slope and offset are applied. A time constant of zero means the new 456 | * values will be applied immediately (within the next measure interval of 1 457 | * second). 458 | * 459 | * @return 0 on success, an error code otherwise 460 | */ 461 | uint16_t setTemperatureOffsetParameters(int16_t tempOffset, int16_t slope, 462 | uint16_t timeConstant); 463 | 464 | /** 465 | * getTemperatureOffsetParameters() - Gets the temperature offset parameters 466 | * from the device. 467 | * 468 | * Supported sensors: SEN54, SEN55 469 | * 470 | * @param tempOffset Constant temperature offset scaled with factor 200 (T 471 | * [°C] = value / 200). 472 | * 473 | * @param slope Normalized temperature offset slope scaled with factor 10000 474 | * (applied factor = value / 10000). 475 | * 476 | * @param timeConstant Time constant [s] how fast the slope and offset are 477 | * applied. After the specified value in seconds, 63% of the new slope and 478 | * offset are applied. 479 | * 480 | * @return 0 on success, an error code otherwise 481 | */ 482 | uint16_t getTemperatureOffsetParameters(int16_t& tempOffset, int16_t& slope, 483 | uint16_t& timeConstant); 484 | 485 | /** 486 | * setWarmStartParameter() - Sets the warm start parameter for the device. 487 | * 488 | * Supported sensors: SEN54, SEN55 489 | * 490 | * @note This parameter can be changed in any state of the device (and the 491 | * getter immediately returns the new value), but it is applied only the 492 | * next time starting a measurement, i.e. when sending a \"Start 493 | * Measurement\" command! So the parameter needs to be set *before* a 494 | * warm-start measurement is started. 495 | * 496 | * @param warmStart Warm start behavior as a value in the range from 0 (cold 497 | * start) to 65535 (warm start). The default value is 0. 498 | * 499 | * @return 0 on success, an error code otherwise 500 | */ 501 | uint16_t setWarmStartParameter(uint16_t warmStart); 502 | 503 | /** 504 | * getWarmStartParameter() - Gets the warm start parameter from the device. 505 | * 506 | * Supported sensors: SEN54, SEN55 507 | * 508 | * @param warmStart Warm start behavior as a value in the range from 0 (cold 509 | * start) to 65535 (warm start). 510 | * 511 | * @return 0 on success, an error code otherwise 512 | */ 513 | uint16_t getWarmStartParameter(uint16_t& warmStart); 514 | 515 | /** 516 | * setVocAlgorithmTuningParameters() - Sets the tuning parameters of the VOC 517 | * algorithm. 518 | * 519 | * Supported sensors: SEN54, SEN55 520 | * 521 | * @note This command is available only in idle mode. In measure mode, this 522 | * command has no effect. In addition, it has no effect if at least one 523 | * parameter is outside the specified range. 524 | * 525 | * @param indexOffset VOC index representing typical (average) conditions. 526 | * Allowed values are in range 1..250. The default value is 100. 527 | * 528 | * @param learningTimeOffsetHours Time constant to estimate the VOC 529 | * algorithm offset from the history in hours. Past events will be forgotten 530 | * after about twice the learning time. Allowed values are in range 1..1000. 531 | * The default value is 12 hours. 532 | * 533 | * @param learningTimeGainHours Time constant to estimate the VOC algorithm 534 | * gain from the history in hours. Past events will be forgotten after about 535 | * twice the learning time. Allowed values are in range 1..1000. The default 536 | * value is 12 hours. 537 | * 538 | * @param gatingMaxDurationMinutes Maximum duration of gating in minutes 539 | * (freeze of estimator during high VOC index signal). Set to zero to 540 | * disable the gating. Allowed values are in range 0..3000. The default 541 | * value is 180 minutes. 542 | * 543 | * @param stdInitial Initial estimate for standard deviation. Lower value 544 | * boosts events during initial learning period, but may result in larger 545 | * device-to-device variations. Allowed values are in range 10..5000. The 546 | * default value is 50. 547 | * 548 | * @param gainFactor Gain factor to amplify or to attenuate the VOC index 549 | * output. Allowed values are in range 1..1000. The default value is 230. 550 | * 551 | * @return 0 on success, an error code otherwise 552 | */ 553 | uint16_t setVocAlgorithmTuningParameters(int16_t indexOffset, 554 | int16_t learningTimeOffsetHours, 555 | int16_t learningTimeGainHours, 556 | int16_t gatingMaxDurationMinutes, 557 | int16_t stdInitial, 558 | int16_t gainFactor); 559 | 560 | /** 561 | * getVocAlgorithmTuningParameters() - Gets the currently set tuning 562 | * parameters of the VOC algorithm. 563 | * 564 | * Supported sensors: SEN54, SEN55 565 | * 566 | * @param indexOffset VOC index representing typical (average) conditions. 567 | * 568 | * @param learningTimeOffsetHours Time constant to estimate the VOC 569 | * algorithm offset from the history in hours. Past events will be forgotten 570 | * after about twice the learning time. 571 | * 572 | * @param learningTimeGainHours Time constant to estimate the VOC algorithm 573 | * gain from the history in hours. Past events will be forgotten after about 574 | * twice the learning time. 575 | * 576 | * @param gatingMaxDurationMinutes Maximum duration of gating in minutes 577 | * (freeze of estimator during high VOC index signal). Zero disables the 578 | * gating. 579 | * 580 | * @param stdInitial Initial estimate for standard deviation. Lower value 581 | * boosts events during initial learning period, but may result in larger 582 | * device-to-device variations. 583 | * 584 | * @param gainFactor Gain factor to amplify or to attenuate the VOC index 585 | * output. 586 | * 587 | * @return 0 on success, an error code otherwise 588 | */ 589 | uint16_t getVocAlgorithmTuningParameters(int16_t& indexOffset, 590 | int16_t& learningTimeOffsetHours, 591 | int16_t& learningTimeGainHours, 592 | int16_t& gatingMaxDurationMinutes, 593 | int16_t& stdInitial, 594 | int16_t& gainFactor); 595 | 596 | /** 597 | * setNoxAlgorithmTuningParameters() - Sets the tuning parameters of the NOx 598 | * algorithm. 599 | * 600 | * Supported sensors: SEN55 601 | * 602 | * @note This command is available only in idle mode. In measure mode, this 603 | * command has no effect. In addition, it has no effect if at least one 604 | * parameter is outside the specified range. 605 | * 606 | * @param indexOffset NOx index representing typical (average) conditions. 607 | * Allowed values are in range 1..250. The default value is 1. 608 | * 609 | * @param learningTimeOffsetHours Time constant to estimate the NOx 610 | * algorithm offset from the history in hours. Past events will be forgotten 611 | * after about twice the learning time. Allowed values are in range 1..1000. 612 | * The default value is 12 hours. 613 | * 614 | * @param learningTimeGainHours The time constant to estimate the NOx 615 | * algorithm gain from the history has no impact for NOx. This parameter is 616 | * still in place for consistency reasons with the VOC tuning parameters 617 | * command. This parameter must always be set to 12 hours. 618 | * 619 | * @param gatingMaxDurationMinutes Maximum duration of gating in minutes 620 | * (freeze of estimator during high NOx index signal). Set to zero to 621 | * disable the gating. Allowed values are in range 0..3000. The default 622 | * value is 720 minutes. 623 | * 624 | * @param stdInitial The initial estimate for standard deviation parameter 625 | * has no impact for NOx. This parameter is still in place for consistency 626 | * reasons with the VOC tuning parameters command. This parameter must 627 | * always be set to 50. 628 | * 629 | * @param gainFactor Gain factor to amplify or to attenuate the NOx index 630 | * output. Allowed values are in range 1..1000. The default value is 230. 631 | * 632 | * @return 0 on success, an error code otherwise 633 | */ 634 | uint16_t setNoxAlgorithmTuningParameters(int16_t indexOffset, 635 | int16_t learningTimeOffsetHours, 636 | int16_t learningTimeGainHours, 637 | int16_t gatingMaxDurationMinutes, 638 | int16_t stdInitial, 639 | int16_t gainFactor); 640 | 641 | /** 642 | * getNoxAlgorithmTuningParameters() - Gets the currently set tuning 643 | * parameters of the NOx algorithm. 644 | * 645 | * Supported sensors: SEN55 646 | * 647 | * @param indexOffset NOx index representing typical (average) conditions. 648 | * 649 | * @param learningTimeOffsetHours Time constant to estimate the NOx 650 | * algorithm offset from the history in hours. Past events will be forgotten 651 | * after about twice the learning time. 652 | * 653 | * @param learningTimeGainHours The time constant to estimate the NOx 654 | * algorithm gain from the history has no impact for NOx. This parameter is 655 | * still in place for consistency reasons with the VOC tuning parameters 656 | * command. 657 | * 658 | * @param gatingMaxDurationMinutes Maximum duration of gating in minutes 659 | * (freeze of estimator during high NOx index signal). Zero disables the 660 | * gating. 661 | * 662 | * @param stdInitial The initial estimate for standard deviation has no 663 | * impact for NOx. This parameter is still in place for consistency reasons 664 | * with the VOC tuning parameters command. 665 | * 666 | * @param gainFactor Gain factor to amplify or to attenuate the NOx index 667 | * output. 668 | * 669 | * @return 0 on success, an error code otherwise 670 | */ 671 | uint16_t getNoxAlgorithmTuningParameters(int16_t& indexOffset, 672 | int16_t& learningTimeOffsetHours, 673 | int16_t& learningTimeGainHours, 674 | int16_t& gatingMaxDurationMinutes, 675 | int16_t& stdInitial, 676 | int16_t& gainFactor); 677 | 678 | /** 679 | * setRhtAccelerationMode() - Sets the RH/T acceleration mode. 680 | * 681 | * Supported sensors: SEN54, SEN55 682 | * 683 | * @note This parameter can be changed in any state of the device (and the 684 | * getter immediately returns the new value), but it is applied only the 685 | * next time starting a measurement, i.e. when sending a \"Start 686 | * Measurement\" command. So the parameter needs to be set *before* a new 687 | * measurement is started. 688 | * 689 | * @param mode The new RH/T acceleration mode. 690 | * 691 | * @return 0 on success, an error code otherwise 692 | */ 693 | uint16_t setRhtAccelerationMode(uint16_t mode); 694 | 695 | /** 696 | * getRhtAccelerationMode() - Gets the RH/T acceleration mode. 697 | * 698 | * Supported sensors: SEN54, SEN55 699 | * 700 | * @param mode The current RH/T acceleration mode. 701 | * 702 | * @return 0 on success, an error code otherwise 703 | */ 704 | uint16_t getRhtAccelerationMode(uint16_t& mode); 705 | 706 | /** 707 | * setVocAlgorithmState() - Sets the VOC algorithm state previously received 708 | * with the \"Get VOC Algorithm State\" command. 709 | * 710 | * Supported sensors: SEN54, SEN55 711 | * 712 | * @note This command is only available in idle mode and the state will be 713 | * applied only once when starting the next measurement. Any further 714 | * measurements (i.e. when stopping and restarting the measure mode) will 715 | * reset the state to initial values. In measure mode, this command has no 716 | * effect. 717 | * 718 | * @param state VOC algorithm state to restore. 719 | * 720 | * @return 0 on success, an error code otherwise 721 | */ 722 | uint16_t setVocAlgorithmState(const uint8_t state[], uint8_t stateSize); 723 | 724 | /** 725 | * getVocAlgorithmState() - Gets the current VOC algorithm state. This data 726 | * can be used to restore the state with the \"Set VOC Algorithm State\" 727 | * command after a short power cycle or device reset. 728 | * 729 | * This command can be used either in measure mode or in idle mode 730 | * (which will then return the state at the time when the measurement 731 | * was stopped). In measure mode, the state can be read each measure 732 | * interval to always have the latest state available, even in case of 733 | * a sudden power loss. 734 | * 735 | * Supported sensors: SEN54, SEN55 736 | * 737 | * @param state Current VOC algorithm state. 738 | * 739 | * @return 0 on success, an error code otherwise 740 | */ 741 | uint16_t getVocAlgorithmState(uint8_t state[], uint8_t stateSize); 742 | 743 | /** 744 | * setFanAutoCleaningInterval() - Sets the fan auto cleaning interval for 745 | * the device. 746 | * 747 | * @param interval Fan auto cleaning interval [s]. Set to zero to disable 748 | * auto cleaning. 749 | * 750 | * @return 0 on success, an error code otherwise 751 | */ 752 | uint16_t setFanAutoCleaningInterval(uint32_t interval); 753 | 754 | /** 755 | * getFanAutoCleaningInterval() - Gets the fan auto cleaning interval from 756 | * the device. 757 | * 758 | * @param interval Fan auto cleaning interval [s]. Zero means auto cleaning 759 | * is disabled. 760 | * 761 | * @return 0 on success, an error code otherwise 762 | */ 763 | uint16_t getFanAutoCleaningInterval(uint32_t& interval); 764 | 765 | /** 766 | * getProductName() - Gets the product name from the device. 767 | * 768 | * @param productName Null-terminated ASCII string containing the product 769 | * name. Up to 32 characters can be read from the device. 770 | * 771 | * @return 0 on success, an error code otherwise 772 | */ 773 | uint16_t getProductName(unsigned char productName[], 774 | uint8_t productNameSize); 775 | 776 | /** 777 | * getSerialNumber() - Gets the serial number from the device. 778 | * 779 | * @param serialNumber Null-terminated ASCII string containing the serial 780 | * number. Up to 32 characters can be read from the device. 781 | * 782 | * @return 0 on success, an error code otherwise 783 | */ 784 | uint16_t getSerialNumber(unsigned char serialNumber[], 785 | uint8_t serialNumberSize); 786 | 787 | /** 788 | * getVersion() - Gets the version information for the hardware, firmware 789 | * and communication protocol. 790 | * 791 | * @param firmwareMajor Firmware major version number. 792 | * 793 | * @param firmwareMinor Firmware minor version number. 794 | * 795 | * @param firmwareDebug Firmware debug state. If the debug state is set, the 796 | * firmware is in development. 797 | * 798 | * @param hardwareMajor Hardware major version number. 799 | * 800 | * @param hardwareMinor Hardware minor version number. 801 | * 802 | * @param protocolMajor Protocol major version number. 803 | * 804 | * @param protocolMinor Protocol minor version number. 805 | * 806 | * @param padding Padding byte, ignore this. 807 | * 808 | * @return 0 on success, an error code otherwise 809 | */ 810 | uint16_t getVersion(uint8_t& firmwareMajor, uint8_t& firmwareMinor, 811 | bool& firmwareDebug, uint8_t& hardwareMajor, 812 | uint8_t& hardwareMinor, uint8_t& protocolMajor, 813 | uint8_t& protocolMinor); 814 | 815 | /** 816 | * readDeviceStatus() - Reads the current device status. 817 | * 818 | * Use this command to get detailed information about the device status. 819 | * The device status is encoded in flags. Each device status flag 820 | * represents a single bit in a 32-bit integer value. If more than one 821 | * error is present, the device status register value is the sum of the 822 | * corresponding flag values. For details about the available flags, 823 | * refer to the device status flags documentation. 824 | * 825 | * @note The status flags of type \"Error\" are sticky, i.e. they are not 826 | * cleared automatically even if the error condition no longer exists. So 827 | * they can only be cleared manually with the command 0xD210 \"Read And 828 | * Clear Device Status\" or with a device reset. All other flags are not 829 | * sticky, i.e. they are cleared automatically if the trigger condition 830 | * disappears. 831 | * 832 | * @param deviceStatus Device status (32 flags as an integer value). For 833 | * details, please refer to the device status flags documentation. 834 | * 835 | * @return 0 on success, an error code otherwise 836 | */ 837 | uint16_t readDeviceStatus(uint32_t& deviceStatus); 838 | 839 | /** 840 | * readAndClearDeviceStatus() - Reads the current device status (like 841 | * command 0xD206 \"Read Device Status\") and afterwards clears all flags. 842 | * 843 | * @param deviceStatus Device status (32 flags as an integer value) 844 | * **before** clearing it. For details, please refer to the device status 845 | * flags documentation. 846 | * 847 | * @return 0 on success, an error code otherwise 848 | */ 849 | uint16_t readAndClearDeviceStatus(uint32_t& deviceStatus); 850 | 851 | /** 852 | * deviceReset() - Executes a reset on the device. This has the same effect 853 | * as a power cycle. 854 | * 855 | * @return 0 on success, an error code otherwise 856 | */ 857 | uint16_t deviceReset(void); 858 | 859 | private: 860 | TwoWire* _i2cBus = nullptr; 861 | }; 862 | 863 | #endif /* SENSIRIONI2CSEN5X_H */ 864 | --------------------------------------------------------------------------------