diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..047f2ad
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,14 @@
+---
+Language: Cpp
+BasedOnStyle: LLVM
+IndentWidth: 4
+AlignAfterOpenBracket: Align
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+IndentCaseLabels: true
+SpacesBeforeTrailingComments: 2
+PointerAlignment: Left
+AlignEscapedNewlines: Left
+ForEachMacros: ['TEST_GROUP', 'TEST']
+...
diff --git a/.github/workflows/arduino_quality_check.yml b/.github/workflows/arduino_quality_check.yml
new file mode 100644
index 0000000..a2dc17c
--- /dev/null
+++ b/.github/workflows/arduino_quality_check.yml
@@ -0,0 +1,24 @@
+name: Quality check
+
+on:
+ pull_request:
+ branches:
+ - main
+ push:
+ branches:
+ - main
+
+jobs:
+ arduino-quality:
+ uses: sensirion/.github/.github/workflows/driver.arduino.check.yml@main
+ with:
+ expect-arduino-examples: true
+ lint-lib-manager-check: update
+
+ todo-check:
+ if: github.event_name == 'push' && github.ref != 'refs/head/main'
+ uses: sensirion/.github/.github/workflows/driver.common.todo_check.yml@main
+
+ code-generation-check:
+ if: github.event_name == 'push' && github.ref != 'refs/head/main'
+ uses: sensirion/.github/.github/workflows/driver.generated.metadata_check.yml@main
diff --git a/.github/workflows/github_release.yml b/.github/workflows/github_release.yml
new file mode 100644
index 0000000..d98ee0e
--- /dev/null
+++ b/.github/workflows/github_release.yml
@@ -0,0 +1,10 @@
+name: Github Release
+
+on:
+ push:
+ tags:
+ - '*'
+
+jobs:
+ github-release:
+ uses: sensirion/.github/.github/workflows/driver.common.github_release.yml@main
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..1610d88
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,103 @@
+stages:
+ - validate
+ - test
+
+variables:
+ YQ_URL: https://github.com/mikefarah/yq/releases/download/v4.33.3/yq_linux_amd64
+
+compile_test:
+ stage: test
+ image:
+ name: registry.gitlab.sensirion.lokal/sensirion/docker/docker-arduino:0.4.0
+ tags: [docker, linux]
+ before_script:
+ - rm -rf ../sensirion-core-arduino-library
+ script:
+ - git clone --depth 1 --branch 0.7.0 https://github.com/Sensirion/arduino-core.git ../sensirion-core-arduino-library
+ - arduino-cli compile --libraries=".." --warnings all --fqbn arduino:samd:mkrzero ./examples/exampleUsage/exampleUsage.ino
+ - arduino-cli compile --libraries=".." --warnings all --fqbn arduino:avr:mega ./examples/exampleUsage/exampleUsage.ino
+ - arduino-cli compile --libraries=".." --warnings all --fqbn arduino:avr:nano ./examples/exampleUsage/exampleUsage.ino
+ - arduino-cli compile --libraries=".." --warnings all --fqbn arduino:avr:uno ./examples/exampleUsage/exampleUsage.ino
+ - arduino-cli compile --libraries=".." --warnings all --fqbn esp32:esp32:esp32 ./examples/exampleUsage/exampleUsage.ino
+ - arduino-cli compile --libraries=".." --warnings all --fqbn esp8266:esp8266:generic ./examples/exampleUsage/exampleUsage.ino
+
+arduino_lint:
+ stage: validate
+ image:
+ name: registry.gitlab.sensirion.lokal/mso-sw/drivers/docker-driver-generator:0.2.0
+ tags: [linux, docker]
+ script:
+ - mkdir ~/arlint
+ - PATH=~/arlint:$PATH
+ - curl -fsSL https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/install.sh | BINDIR=~/arlint sh
+ - arduino-lint --library-manager false
+
+syntax_check:
+ stage: validate
+ image:
+ name: registry.gitlab.sensirion.lokal/mso-sw/drivers/docker-driver-generator:0.2.0
+ tags: [linux, docker]
+ script:
+ - find . -type f -iregex ".*\.\(c\|h\|cpp\|ino\)" -exec clang-format-6.0 -i -style=file {} \; && git diff --exit-code
+
+
+cppcheck:
+ stage: validate
+ image:
+ name: registry.gitlab.sensirion.lokal/mso-sw/drivers/docker-driver-generator:0.2.0
+ tags: [linux, docker]
+ script:
+ - cppcheck --std=c++11 --language=c++ --error-exitcode=1 --enable=warning,style,performance,portability --suppress=unreadVariable --suppress=unusedStructMember src/*
+
+TODO_check:
+ stage: validate
+ image:
+ name: registry.gitlab.sensirion.lokal/mso-sw/drivers/docker-driver-generator:0.2.0
+ tags: [linux, docker]
+ script:
+ - '! grep -rnw --exclude=.gitlab-ci.yml --exclude-dir=.git . -e "TODO"'
+
+metadata_check:
+ stage: validate
+ image:
+ name: registry.gitlab.sensirion.lokal/mso-sw/drivers/docker-driver-generator:0.2.0
+ tags: [linux, docker]
+ before_script:
+ - apt-get -qq update && apt-get -qq install -y wget
+ - if ! [ -d downloads/ ]; then mkdir downloads; fi
+ - if ! [ -e downloads/yq ]; then wget --no-verbose $YQ_URL -O downloads/yq; fi
+ - cp downloads/yq /usr/local/bin/yq && chmod +x /usr/local/bin/yq
+ script:
+ # check if metadata.yml exists
+ - >
+ if ! [ -f "metadata.yml" ]; then
+ echo "metadata.yml file not found"
+ exit 1
+ fi
+ # check that dg_status is 'released'
+ - export DG_STATUS=$(yq ".dg_status.[]" ./metadata.yml)
+ - >
+ if [ $DG_STATUS != "released" ]; then
+ echo "dg_status in metadata.yml has to be 'released', not '$DG_STATUS'"
+ exit 1
+ fi
+ # check that last_generated is not older than timestamp of last non-merge commit (+ 3 minutes)
+ - export IS_MANUALLY_MODIFIED=$(yq ".is_manually_modified" ./metadata.yml)
+ - >
+ if [ $IS_MANUALLY_MODIFIED = false ]; then
+ export LAST_GENERATED_TS=$(yq ".last_generated" ./metadata.yml)
+ export LAST_GENERATED_TS_EPOCH=$(date -d "$LAST_GENERATED_TS" +%s)
+ export LAST_NON_MERGE_COMMIT_TS=$(git log --format=%ad --date=iso-strict --no-merges -1)
+ export COMMIT_TS_EPOCH=$(date -d "$LAST_NON_MERGE_COMMIT_TS" +%s)
+ if [ $(($LAST_GENERATED_TS_EPOCH + 180)) -lt $COMMIT_TS_EPOCH ]; then
+ echo "'last_generated' timestamp in metadata.yml is older than commit timestamp ($LAST_GENERATED_TS vs $LAST_NON_MERGE_COMMIT_TS)"
+ exit 1
+ fi
+ fi
+ # check that 'is_manually_modified' is set to true if commit is not from driver generator
+ - export LAST_NON_MERGE_COMMIT_AUTHOR=$(git log --format=%an --no-merges -1)
+ - >
+ if ! [ "$LAST_NON_MERGE_COMMIT_AUTHOR" = "Driver Generator 2" ] && [ "$IS_MANUALLY_MODIFIED" = false ]; then
+ echo "Last commit is not from Driver Generator. Please update 'is_manually_modified' in metadata.yml"
+ exit 1
+ fi
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..792adcb
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,17 @@
+# CHANGELOG
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+## [0.1.0] - 2024-10-31
+
+### Added
+
+- Add product picture
+- Add interfaces to start, stop and read measurements.
+- Add interfaces to read product name, serial number and version
+
+[Unreleased]: https://github.com/Sensirion/arduino-i2c-sen66/compare/0.1.0...HEAD
+[0.1.0]: https://github.com/Sensirion/arduino-i2c-sen66/releases/tag/0.1.0
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..1daaf92
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,29 @@
+BSD 3-Clause License
+
+Copyright (c) 2024, 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:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder 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.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9b87187
--- /dev/null
+++ b/README.md
@@ -0,0 +1,198 @@
+# Sensirion I²C SEN66 Arduino Library
+
+This is the Sensirion SEN66 library for Arduino allowing you to
+communicate with a SEN66 sensor over I²C.
+
+
+
+Click [here](https://sensirion.com/sen6x-air-quality-sensor-platform) to learn more about the Sensirion SEN66 sensor.
+
+
+unknown
+
+
+The default I²C address of [SEN66](https://www.sensirion.com/products/catalog/SEN6x) is **0x6B**.
+
+
+
+## Installation of the library
+
+This library can be installed using the Arduino Library manager:
+Start the [Arduino IDE](http://www.arduino.cc/en/main/software) and open
+the Library Manager via
+
+`Sketch` ➔ `Include Library` ➔ `Manage Libraries...`
+
+Search for the `Sensirion I2C SEN66` library in the `Filter
+your search...` field and install it by clicking the `install` button.
+
+If you cannot find it in the library manager, download the latest release as .zip file
+and add it to your [Arduino IDE](http://www.arduino.cc/en/main/software) via
+
+`Sketch` ➔ `Include Library` ➔ `Add .ZIP Library...`
+
+Don't forget to **install the dependencies** listed below the same way via library
+manager or `Add .ZIP Library`
+
+#### Dependencies
+* [Sensirion Core](https://github.com/Sensirion/arduino-core)
+
+## Sensor wiring
+
+Use the following pin description to connect your SEN66 to the standard I²C bus of your Arduino board:
+
+
+
+| *Pin* | *Cable Color* | *Name* | *Description* | *Comments* |
+|-------|---------------|:------:|----------------|------------|
+| 1 | red | VDD | Supply Voltage | 3.3V ±10%
+| 2 | black | GND | Ground |
+| 3 | green | SDA | I2C: Serial data input / output | TTL 5V compatible
+| 4 | yellow | SCL | I2C: Serial clock input | TTL 5V compatible
+| 5 | | NC | Do not connect |
+| 6 | | NC | Do not connect |
+
+
+
+
+The recommended voltage is 3.3V.
+
+### Board specific wiring
+You will find pinout schematics for recommended board models below:
+
+
+
+Arduino Uno
+
+
+| *SEN66* | *SEN66 Pin* | *Cable Color* | *Board Pin* |
+| :---: | --- | --- | --- |
+| VDD | 1 | red | 3.3V |
+| GND | 2 | black | GND |
+| SDA | 3 | green | D18/SDA |
+| SCL | 4 | yellow | D19/SCL |
+
+
+
+
+
+
+
+
+
+
+Arduino Nano
+
+
+| *SEN66* | *SEN66 Pin* | *Cable Color* | *Board Pin* |
+| :---: | --- | --- | --- |
+| VDD | 1 | red | 3.3V |
+| GND | 2 | black | GND |
+| SDA | 3 | green | A4 |
+| SCL | 4 | yellow | A5 |
+
+
+
+
+
+
+
+
+
+
+Arduino Micro
+
+
+| *SEN66* | *SEN66 Pin* | *Cable Color* | *Board Pin* |
+| :---: | --- | --- | --- |
+| VDD | 1 | red | 3.3V |
+| GND | 2 | black | GND |
+| SDA | 3 | green | D2/SDA |
+| SCL | 4 | yellow | ~D3/SCL |
+
+
+
+
+
+
+
+
+
+
+Arduino Mega 2560
+
+
+| *SEN66* | *SEN66 Pin* | *Cable Color* | *Board Pin* |
+| :---: | --- | --- | --- |
+| VDD | 1 | red | 3.3V |
+| GND | 2 | black | GND |
+| SDA | 3 | green | D20/SDA |
+| SCL | 4 | yellow | D21/SCL |
+
+
+
+
+
+
+
+
+
+
+ESP32 DevKitC
+
+
+| *SEN66* | *SEN66 Pin* | *Cable Color* | *Board Pin* |
+| :---: | --- | --- | --- |
+| VDD | 1 | red | 3V3 |
+| GND | 2 | black | GND |
+| SDA | 3 | green | GPIO 21 |
+| SCL | 4 | yellow | GPIO 22 |
+
+
+
+
+
+
+
+
+
+## Quick Start
+
+1. Install the libraries and dependencies according to [Installation of the library](#installation-of-the-library)
+
+2. Connect the SEN66 sensor to your Arduino as explained in [Sensor wiring](#sensor-wiring)
+
+3. Open the `exampleUsage` sample project within the Arduino IDE:
+
+ `File` ➔ `Examples` ➔ `Sensirion I2C SEN66` ➔ `exampleUsage`
+
+
+
+5. Click the `Upload` button in the Arduino IDE or `Sketch` ➔ `Upload`
+
+4. When the upload process has finished, open the `Serial Monitor` or `Serial
+ Plotter` via the `Tools` menu to observe the measurement values. Note that
+ the `Baud Rate` in the used tool has to be set to `115200 baud`.
+
+## Contributing
+
+**Contributions are welcome!**
+
+This Sensirion library uses
+[`clang-format`](https://releases.llvm.org/download.html) to standardize the
+formatting of all our `.cpp` and `.h` files. Make sure your contributions are
+formatted accordingly:
+
+The `-i` flag will apply the format changes to the files listed.
+
+```bash
+clang-format -i src/*.cpp src/*.h
+```
+
+Note that differences from this formatting will result in a failed build until
+they are fixed.
+:
+
+## License
+
+See [LICENSE](LICENSE).
\ No newline at end of file
diff --git a/examples/exampleUsage/exampleUsage.ino b/examples/exampleUsage/exampleUsage.ino
new file mode 100644
index 0000000..f5949b9
--- /dev/null
+++ b/examples/exampleUsage/exampleUsage.ino
@@ -0,0 +1,148 @@
+/*
+ * THIS FILE IS AUTOMATICALLY GENERATED
+ *
+ * Generator: sensirion-driver-generator 1.0.1
+ * Product: sen66
+ * Model-Version: 1.2.0
+ */
+/*
+ * Copyright (c) 2024, 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
+#include
+#include
+
+// macro definitions
+// make sure that we use the proper definition of NO_ERROR
+#ifdef NO_ERROR
+#undef NO_ERROR
+#endif
+#define NO_ERROR 0
+
+SensirionI2cSen66 sensor;
+
+static char errorMessage[64];
+static int16_t error;
+
+void print_byte_array(uint8_t* array, uint16_t len) {
+ uint16_t i = 0;
+ Serial.print("0x");
+ for (; i < len; i++) {
+ Serial.print(array[i], HEX);
+ }
+}
+
+void setup() {
+
+ Serial.begin(115200);
+ while (!Serial) {
+ delay(100);
+ }
+ Wire.begin();
+ sensor.begin(Wire, SEN66_I2C_ADDR_6B);
+
+ error = sensor.deviceReset();
+ if (error != NO_ERROR) {
+ Serial.print("Error trying to execute deviceReset(): ");
+ errorToString(error, errorMessage, sizeof errorMessage);
+ Serial.println(errorMessage);
+ return;
+ }
+ delay(1200);
+ uint8_t serialNumber[32] = {0};
+ error = sensor.getSerialNumber(serialNumber, 32);
+ if (error != NO_ERROR) {
+ Serial.print("Error trying to execute getSerialNumber(): ");
+ errorToString(error, errorMessage, sizeof errorMessage);
+ Serial.println(errorMessage);
+ return;
+ }
+ Serial.print("serialNumber: ");
+ print_byte_array(serialNumber, 32);
+ Serial.println();
+ error = sensor.startContinuousMeasurement();
+ if (error != NO_ERROR) {
+ Serial.print("Error trying to execute startContinuousMeasurement(): ");
+ errorToString(error, errorMessage, sizeof errorMessage);
+ Serial.println(errorMessage);
+ return;
+ }
+}
+
+void loop() {
+
+ float massConcentrationPm1p0 = 0.0;
+ float massConcentrationPm2p5 = 0.0;
+ float massConcentrationPm4p0 = 0.0;
+ float massConcentrationPm10p0 = 0.0;
+ float humidity = 0.0;
+ float temperature = 0.0;
+ float vocIndex = 0.0;
+ float noxIndex = 0.0;
+ float co2 = 0.0;
+ delay(1000);
+ error = sensor.readMeasuredValues(
+ massConcentrationPm1p0, massConcentrationPm2p5, massConcentrationPm4p0,
+ massConcentrationPm10p0, humidity, temperature, vocIndex, noxIndex,
+ co2);
+ if (error != NO_ERROR) {
+ Serial.print("Error trying to execute readMeasuredValues(): ");
+ errorToString(error, errorMessage, sizeof errorMessage);
+ Serial.println(errorMessage);
+ return;
+ }
+ Serial.print("massConcentrationPm1p0: ");
+ Serial.print(massConcentrationPm1p0);
+ Serial.print("\t");
+ Serial.print("massConcentrationPm2p5: ");
+ Serial.print(massConcentrationPm2p5);
+ Serial.print("\t");
+ Serial.print("massConcentrationPm4p0: ");
+ Serial.print(massConcentrationPm4p0);
+ Serial.print("\t");
+ Serial.print("massConcentrationPm10p0: ");
+ Serial.print(massConcentrationPm10p0);
+ Serial.print("\t");
+ Serial.print("humidity: ");
+ Serial.print(humidity);
+ Serial.print("\t");
+ Serial.print("temperature: ");
+ Serial.print(temperature);
+ Serial.print("\t");
+ Serial.print("vocIndex: ");
+ Serial.print(vocIndex);
+ Serial.print("\t");
+ Serial.print("noxIndex: ");
+ Serial.print(noxIndex);
+ Serial.print("\t");
+ Serial.print("co2: ");
+ Serial.print(co2);
+ Serial.println();
+}
diff --git a/images/Arduino-Mega-2560-Rev3-i2c-pinout-3.3V.png b/images/Arduino-Mega-2560-Rev3-i2c-pinout-3.3V.png
new file mode 100644
index 0000000..942173d
Binary files /dev/null and b/images/Arduino-Mega-2560-Rev3-i2c-pinout-3.3V.png differ
diff --git a/images/Arduino-Micro-i2c-pinout-3.3V.png b/images/Arduino-Micro-i2c-pinout-3.3V.png
new file mode 100644
index 0000000..ca9ba6c
Binary files /dev/null and b/images/Arduino-Micro-i2c-pinout-3.3V.png differ
diff --git a/images/Arduino-Nano-i2c-pinout-3.3V.png b/images/Arduino-Nano-i2c-pinout-3.3V.png
new file mode 100644
index 0000000..55fd2ff
Binary files /dev/null and b/images/Arduino-Nano-i2c-pinout-3.3V.png differ
diff --git a/images/Arduino-Uno-Rev3-i2c-pinout-3.3V.png b/images/Arduino-Uno-Rev3-i2c-pinout-3.3V.png
new file mode 100644
index 0000000..a6daad7
Binary files /dev/null and b/images/Arduino-Uno-Rev3-i2c-pinout-3.3V.png differ
diff --git a/images/esp32-devkitc-i2c-pinout-3.3V.png b/images/esp32-devkitc-i2c-pinout-3.3V.png
new file mode 100644
index 0000000..319b021
Binary files /dev/null and b/images/esp32-devkitc-i2c-pinout-3.3V.png differ
diff --git a/images/sen6x-pinout.png b/images/sen6x-pinout.png
new file mode 100644
index 0000000..42b5f0a
Binary files /dev/null and b/images/sen6x-pinout.png differ
diff --git a/images/sen6x.png b/images/sen6x.png
new file mode 100644
index 0000000..b97bde3
Binary files /dev/null and b/images/sen6x.png differ
diff --git a/keywords.txt b/keywords.txt
new file mode 100644
index 0000000..9636ea9
--- /dev/null
+++ b/keywords.txt
@@ -0,0 +1,43 @@
+#######################################
+# Syntax Coloring Map
+#######################################
+
+#######################################
+# Datatypes (KEYWORD1)
+#######################################
+
+SensirionI2cSen66 KEYWORD1
+
+#######################################
+# Methods and Functions (KEYWORD2)
+#######################################
+
+readMeasuredValues KEYWORD2
+deviceReset KEYWORD2
+startContinuousMeasurement KEYWORD2
+stopMeasurement KEYWORD2
+getDataReady KEYWORD2
+readMeasuredValuesAsIntegers KEYWORD2
+performForcedCo2Recalibration KEYWORD2
+getProductName KEYWORD2
+getSerialNumber KEYWORD2
+getVersion KEYWORD2
+signalMassConcentrationPm1p0 KEYWORD2
+signalMassConcentrationPm2p5 KEYWORD2
+signalMassConcentrationPm4p0 KEYWORD2
+signalMassConcentrationPm10p0 KEYWORD2
+signalTemperature KEYWORD2
+signalHumidity KEYWORD2
+signalVocIndex KEYWORD2
+signalNoxIndex KEYWORD2
+signalCo2 KEYWORD2
+
+#######################################
+# Instances (KEYWORD2)
+#######################################
+
+sensor KEYWORD2
+
+#######################################
+# Constants (LITERAL1)
+#######################################
\ No newline at end of file
diff --git a/library.properties b/library.properties
new file mode 100644
index 0000000..b609c4c
--- /dev/null
+++ b/library.properties
@@ -0,0 +1,11 @@
+name=Sensirion I2C SEN66
+version=0.1.0
+author=Sensirion
+maintainer=Sensirion
+sentence=Library for the SEN66 sensor by Sensirion
+paragraph=Enables you to use the SEN66 sensor via I2C.
+url=https://github.com/Sensirion/arduino-i2c-sen66
+category=Sensors
+architectures=*
+depends=Sensirion Core
+includes=SensirionI2cSen66.h
diff --git a/metadata.yml b/metadata.yml
new file mode 100644
index 0000000..5a15951
--- /dev/null
+++ b/metadata.yml
@@ -0,0 +1,7 @@
+# driver generation metadata
+generator_version: 1.0.1
+model_version: 1.2.0
+dg_status: released
+is_manually_modified: false
+first_generated: '2024-10-30 08:14'
+last_generated: '2024-10-30 08:14'
diff --git a/src/SensirionI2cSen66.cpp b/src/SensirionI2cSen66.cpp
new file mode 100644
index 0000000..5575358
--- /dev/null
+++ b/src/SensirionI2cSen66.cpp
@@ -0,0 +1,351 @@
+/*
+ * THIS FILE IS AUTOMATICALLY GENERATED
+ *
+ * Generator: sensirion-driver-generator 1.0.1
+ * Product: sen66
+ * Model-Version: 1.2.0
+ */
+/*
+ * Copyright (c) 2024, 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 "SensirionI2cSen66.h"
+#include
+
+// make sure that we use the proper definition of NO_ERROR
+#ifdef NO_ERROR
+#undef NO_ERROR
+#endif
+#define NO_ERROR 0
+
+static uint8_t communication_buffer[48] = {0};
+
+SensirionI2cSen66::SensirionI2cSen66() {
+}
+
+float SensirionI2cSen66::signalMassConcentrationPm1p0(
+ uint16_t massConcentrationPm1p0Raw) {
+ float massConcentrationPm1p0 = 0.0;
+ massConcentrationPm1p0 = massConcentrationPm1p0Raw / 10.0;
+ return massConcentrationPm1p0;
+}
+
+float SensirionI2cSen66::signalMassConcentrationPm2p5(
+ uint16_t massConcentrationPm2p5Raw) {
+ float massConcentrationPm2p5 = 0.0;
+ massConcentrationPm2p5 = massConcentrationPm2p5Raw / 10.0;
+ return massConcentrationPm2p5;
+}
+
+float SensirionI2cSen66::signalMassConcentrationPm4p0(
+ uint16_t massConcentrationPm4p0Raw) {
+ float massConcentrationPm4p0 = 0.0;
+ massConcentrationPm4p0 = massConcentrationPm4p0Raw / 10.0;
+ return massConcentrationPm4p0;
+}
+
+float SensirionI2cSen66::signalMassConcentrationPm10p0(
+ uint16_t massConcentrationPm10p0Raw) {
+ float massConcentrationPm10p0 = 0.0;
+ massConcentrationPm10p0 = massConcentrationPm10p0Raw / 10.0;
+ return massConcentrationPm10p0;
+}
+
+float SensirionI2cSen66::signalTemperature(int16_t temperatureRaw) {
+ float temperature = 0.0;
+ temperature = temperatureRaw / 200.0;
+ return temperature;
+}
+
+float SensirionI2cSen66::signalHumidity(int16_t humidityRaw) {
+ float humidity = 0.0;
+ humidity = humidityRaw / 100.0;
+ return humidity;
+}
+
+float SensirionI2cSen66::signalVocIndex(int16_t vocIndexRaw) {
+ float vocIndex = 0.0;
+ vocIndex = vocIndexRaw / 10.0;
+ return vocIndex;
+}
+
+float SensirionI2cSen66::signalNoxIndex(int16_t noxIndexRaw) {
+ float noxIndex = 0.0;
+ noxIndex = noxIndexRaw / 10.0;
+ return noxIndex;
+}
+
+float SensirionI2cSen66::signalCo2(uint16_t co2Raw) {
+ float co2 = 0.0;
+ co2 = co2Raw / 1.0;
+ return co2;
+}
+
+int16_t SensirionI2cSen66::readMeasuredValues(
+ float& massConcentrationPm1p0, float& massConcentrationPm2p5,
+ float& massConcentrationPm4p0, float& massConcentrationPm10p0,
+ float& humidity, float& temperature, float& vocIndex, float& noxIndex,
+ float& co2) {
+ uint16_t massConcentrationPm1p0Raw = 0;
+ uint16_t massConcentrationPm2p5Raw = 0;
+ uint16_t massConcentrationPm4p0Raw = 0;
+ uint16_t massConcentrationPm10p0Raw = 0;
+ int16_t humidityRaw = 0;
+ int16_t temperatureRaw = 0;
+ int16_t vocIndexRaw = 0;
+ int16_t noxIndexRaw = 0;
+ uint16_t co2Raw = 0;
+ int16_t localError = 0;
+ localError = readMeasuredValuesAsIntegers(
+ massConcentrationPm1p0Raw, massConcentrationPm2p5Raw,
+ massConcentrationPm4p0Raw, massConcentrationPm10p0Raw, humidityRaw,
+ temperatureRaw, vocIndexRaw, noxIndexRaw, co2Raw);
+ if (localError != NO_ERROR) {
+ return localError;
+ }
+ massConcentrationPm1p0 = SensirionI2cSen66::signalMassConcentrationPm1p0(
+ massConcentrationPm1p0Raw);
+ massConcentrationPm2p5 = SensirionI2cSen66::signalMassConcentrationPm2p5(
+ massConcentrationPm2p5Raw);
+ massConcentrationPm4p0 = SensirionI2cSen66::signalMassConcentrationPm4p0(
+ massConcentrationPm4p0Raw);
+ massConcentrationPm10p0 = SensirionI2cSen66::signalMassConcentrationPm10p0(
+ massConcentrationPm10p0Raw);
+ humidity = SensirionI2cSen66::signalHumidity(humidityRaw);
+ temperature = SensirionI2cSen66::signalTemperature(temperatureRaw);
+ vocIndex = SensirionI2cSen66::signalVocIndex(vocIndexRaw);
+ noxIndex = SensirionI2cSen66::signalNoxIndex(noxIndexRaw);
+ co2 = SensirionI2cSen66::signalCo2(co2Raw);
+ return localError;
+}
+
+int16_t SensirionI2cSen66::deviceReset() {
+ int16_t localError = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ SensirionI2CTxFrame txFrame =
+ SensirionI2CTxFrame::createWithUInt16Command(0xd304, buffer_ptr, 2);
+ localError =
+ SensirionI2CCommunication::sendFrame(_i2cAddress, txFrame, *_i2cBus);
+ if (localError != NO_ERROR) {
+ return localError;
+ }
+ delay(1200);
+ return localError;
+}
+
+int16_t SensirionI2cSen66::startContinuousMeasurement() {
+ int16_t localError = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ SensirionI2CTxFrame txFrame =
+ SensirionI2CTxFrame::createWithUInt16Command(0x21, buffer_ptr, 2);
+ localError =
+ SensirionI2CCommunication::sendFrame(_i2cAddress, txFrame, *_i2cBus);
+ if (localError != NO_ERROR) {
+ return localError;
+ }
+ delay(50);
+ return localError;
+}
+
+int16_t SensirionI2cSen66::stopMeasurement() {
+ int16_t localError = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ SensirionI2CTxFrame txFrame =
+ SensirionI2CTxFrame::createWithUInt16Command(0x104, buffer_ptr, 2);
+ localError =
+ SensirionI2CCommunication::sendFrame(_i2cAddress, txFrame, *_i2cBus);
+ if (localError != NO_ERROR) {
+ return localError;
+ }
+ delay(160);
+ return localError;
+}
+
+int16_t SensirionI2cSen66::getDataReady(uint8_t& padding, bool& dataReady) {
+ int16_t localError = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ SensirionI2CTxFrame txFrame =
+ SensirionI2CTxFrame::createWithUInt16Command(0x202, buffer_ptr, 3);
+ localError =
+ SensirionI2CCommunication::sendFrame(_i2cAddress, txFrame, *_i2cBus);
+ if (localError != NO_ERROR) {
+ return localError;
+ }
+ delay(20);
+ SensirionI2CRxFrame rxFrame(buffer_ptr, 3);
+ localError = SensirionI2CCommunication::receiveFrame(_i2cAddress, 3,
+ rxFrame, *_i2cBus);
+ if (localError != NO_ERROR) {
+ return localError;
+ }
+ localError |= rxFrame.getUInt8(padding);
+ localError |= rxFrame.getBool(dataReady);
+ return localError;
+}
+
+int16_t SensirionI2cSen66::readMeasuredValuesAsIntegers(
+ uint16_t& massConcentrationPm1p0, uint16_t& massConcentrationPm2p5,
+ uint16_t& massConcentrationPm4p0, uint16_t& massConcentrationPm10p0,
+ int16_t& ambientHumidity, int16_t& ambientTemperature, int16_t& vOCIndex,
+ int16_t& nOxIndex, uint16_t& cO2) {
+ int16_t localError = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ SensirionI2CTxFrame txFrame =
+ SensirionI2CTxFrame::createWithUInt16Command(0x300, buffer_ptr, 27);
+ localError =
+ SensirionI2CCommunication::sendFrame(_i2cAddress, txFrame, *_i2cBus);
+ if (localError != NO_ERROR) {
+ return localError;
+ }
+ delay(20);
+ SensirionI2CRxFrame rxFrame(buffer_ptr, 27);
+ localError = SensirionI2CCommunication::receiveFrame(_i2cAddress, 27,
+ rxFrame, *_i2cBus);
+ if (localError != NO_ERROR) {
+ return localError;
+ }
+ localError |= rxFrame.getUInt16(massConcentrationPm1p0);
+ localError |= rxFrame.getUInt16(massConcentrationPm2p5);
+ localError |= rxFrame.getUInt16(massConcentrationPm4p0);
+ localError |= rxFrame.getUInt16(massConcentrationPm10p0);
+ localError |= rxFrame.getInt16(ambientHumidity);
+ localError |= rxFrame.getInt16(ambientTemperature);
+ localError |= rxFrame.getInt16(vOCIndex);
+ localError |= rxFrame.getInt16(nOxIndex);
+ localError |= rxFrame.getUInt16(cO2);
+ return localError;
+}
+
+int16_t SensirionI2cSen66::performForcedCo2Recalibration(
+ uint16_t targetCo2Concentration, uint16_t& correction) {
+ int16_t localError = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ SensirionI2CTxFrame txFrame =
+ SensirionI2CTxFrame::createWithUInt16Command(0x6707, buffer_ptr, 5);
+ localError |= txFrame.addUInt16(targetCo2Concentration);
+ if (localError != NO_ERROR) {
+ return localError;
+ }
+ localError =
+ SensirionI2CCommunication::sendFrame(_i2cAddress, txFrame, *_i2cBus);
+ if (localError != NO_ERROR) {
+ return localError;
+ }
+ delay(500);
+ SensirionI2CRxFrame rxFrame(buffer_ptr, 5);
+ localError = SensirionI2CCommunication::receiveFrame(_i2cAddress, 3,
+ rxFrame, *_i2cBus);
+ if (localError != NO_ERROR) {
+ return localError;
+ }
+ localError |= rxFrame.getUInt16(correction);
+ return localError;
+}
+
+int16_t SensirionI2cSen66::getProductName(uint8_t productName[],
+ uint16_t productNameSize) {
+ int16_t localError = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ SensirionI2CTxFrame txFrame =
+ SensirionI2CTxFrame::createWithUInt16Command(0xd014, buffer_ptr, 48);
+ localError =
+ SensirionI2CCommunication::sendFrame(_i2cAddress, txFrame, *_i2cBus);
+ if (localError != NO_ERROR) {
+ return localError;
+ }
+ delay(20);
+ SensirionI2CRxFrame rxFrame(buffer_ptr, 48);
+ localError = SensirionI2CCommunication::receiveFrame(_i2cAddress, 48,
+ rxFrame, *_i2cBus);
+ if (localError != NO_ERROR) {
+ return localError;
+ }
+ localError |= rxFrame.getBytes((uint8_t*)productName, productNameSize);
+ return localError;
+}
+
+int16_t SensirionI2cSen66::getSerialNumber(uint8_t serialNumber[],
+ uint16_t serialNumberSize) {
+ int16_t localError = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ SensirionI2CTxFrame txFrame =
+ SensirionI2CTxFrame::createWithUInt16Command(0xd033, buffer_ptr, 48);
+ localError =
+ SensirionI2CCommunication::sendFrame(_i2cAddress, txFrame, *_i2cBus);
+ if (localError != NO_ERROR) {
+ return localError;
+ }
+ delay(20);
+ SensirionI2CRxFrame rxFrame(buffer_ptr, 48);
+ localError = SensirionI2CCommunication::receiveFrame(_i2cAddress, 48,
+ rxFrame, *_i2cBus);
+ if (localError != NO_ERROR) {
+ return localError;
+ }
+ localError |= rxFrame.getBytes((uint8_t*)serialNumber, serialNumberSize);
+ return localError;
+}
+
+int16_t
+SensirionI2cSen66::getVersion(uint8_t& firmwareMajor, uint8_t& firmwareMinor,
+ bool& firmwareDebug, uint8_t& hardwareMajor,
+ uint8_t& hardwareMinor, uint8_t& protocolMajor,
+ uint8_t& protocolMinor, uint8_t& padding) {
+ int16_t localError = NO_ERROR;
+ uint8_t* buffer_ptr = communication_buffer;
+ SensirionI2CTxFrame txFrame =
+ SensirionI2CTxFrame::createWithUInt16Command(0xd000, buffer_ptr, 12);
+ localError =
+ SensirionI2CCommunication::sendFrame(_i2cAddress, txFrame, *_i2cBus);
+ if (localError != NO_ERROR) {
+ return localError;
+ }
+ delay(20);
+ SensirionI2CRxFrame rxFrame(buffer_ptr, 12);
+ localError = SensirionI2CCommunication::receiveFrame(_i2cAddress, 12,
+ rxFrame, *_i2cBus);
+ if (localError != NO_ERROR) {
+ return localError;
+ }
+ localError |= rxFrame.getUInt8(firmwareMajor);
+ localError |= rxFrame.getUInt8(firmwareMinor);
+ localError |= rxFrame.getBool(firmwareDebug);
+ localError |= rxFrame.getUInt8(hardwareMajor);
+ localError |= rxFrame.getUInt8(hardwareMinor);
+ localError |= rxFrame.getUInt8(protocolMajor);
+ localError |= rxFrame.getUInt8(protocolMinor);
+ localError |= rxFrame.getUInt8(padding);
+ return localError;
+}
+
+void SensirionI2cSen66::begin(TwoWire& i2cBus, uint8_t i2cAddress) {
+ _i2cBus = &i2cBus;
+ _i2cAddress = i2cAddress;
+}
diff --git a/src/SensirionI2cSen66.h b/src/SensirionI2cSen66.h
new file mode 100644
index 0000000..c80d850
Binary files /dev/null and b/src/SensirionI2cSen66.h differ