diff --git a/.github/workflows/build-and-publish.yml b/.github/workflows/build-and-publish.yml index 4f03581..d990a98 100644 --- a/.github/workflows/build-and-publish.yml +++ b/.github/workflows/build-and-publish.yml @@ -8,6 +8,4 @@ on: jobs: build_and_deploy: uses: sensirion/.github/.github/workflows/driver.python.pypi_publish.yml@main - secrets: - PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }} - + secrets: inherit diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index d200c56..d2d0f78 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -2,9 +2,11 @@ name: Publish Documentation on: workflow_dispatch: push: - tags: - - "[0-9]+.[0-9]+.[0-9]+" + branches: + - main jobs: documentation: uses: sensirion/.github/.github/workflows/driver.python.documentation.yml@main + with: + use-project-requirements: true diff --git a/.github/workflows/gh_workflow_metadata_update.yml b/.github/workflows/gh_workflow_metadata_update.yml new file mode 100644 index 0000000..7dd70ed --- /dev/null +++ b/.github/workflows/gh_workflow_metadata_update.yml @@ -0,0 +1,11 @@ +name: Driver Index Metadata Update + +on: + push: + branches: + - main + +jobs: + driver-index-metadata-update: + uses: sensirion/.github/.github/workflows/driver.common.di_metadata_update.yml@main + secrets: inherit diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c15f72f..b1cebfa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,9 +8,5 @@ on: - main jobs: - dg-metadata-validation: - if: github.event_name == 'push' && github.ref != 'refs/head/main' - uses: sensirion/.github/.github/workflows/driver.generated.metadata_check.yml@main - test: uses: sensirion/.github/.github/workflows/driver.python.test.yml@main diff --git a/CHANGELOG.md b/CHANGELOG.md index cde2ef2..e1ef572 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.3.0] - 2026-6-5 + +### Added + +- Added get_product_type command. +## [1.0.1] - 2026-2-13 + +### Fixed + +- Version mismatch in library.properties +## [1.0.0] - 2025-3-13 + ### Added - Support for all I2C commands for the SEN63C as described in the datasheet. +[Unreleased]: https://github.com/Sensirion/python-i2c-sen63c/compare/1.3.0...HEAD +[1.3.0]: https://github.com/Sensirion/python-i2c-sen63c/compare/1.0.1...1.3.0 +[1.0.1]: https://github.com/Sensirion/python-i2c-sen63c/compare/1.0.0...1.0.1 +[1.0.0]: https://github.com/Sensirion/python-i2c-sen63c/releases/tag/1.0.0 \ No newline at end of file diff --git a/LICENSE b/LICENSE index 2062766..8fe04ed 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2025, Sensirion AG +Copyright (c) 2026, Sensirion AG All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/README.md b/README.md index 6a0bed4..e27d91e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ This repository contains the Python driver to communicate with a Sensirion SEN63C sensor over I2C. -SEN63C picture @@ -10,18 +10,18 @@ Click [here](https://sensirion.com/sen6x-air-quality-sensor-platform) to learn m -The default I²C address of [SEN63C](https://www.sensirion.com/products/catalog/SEN63C) is **0x6B**. +The default I²C address of [SEN63C](https://www.sensirion.com/products/catalog/SEN63C) is **0x6b**. ## Connect the sensor -You can connect your sensor over a [SEK-SensorBridge](https://developer.sensirion.com/sensirion-products/sek-sensorbridge/). +You can connect your sensor over a [SEK-SensorBridge](https://developer.sensirion.com/product-support/sek-sensorbridge/). For special setups you find the sensor pinout in the section below.
Sensor pinout

-sensor wiring picture | *Pin* | *Cable Color* | *Name* | *Description* | *Comments* | diff --git a/ci/checkin_doc.sh b/ci/checkin_doc.sh deleted file mode 100644 index 1031751..0000000 --- a/ci/checkin_doc.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -# set shell settings (see https://sipb.mit.edu/doc/safe-shell/) -set -euv -o pipefail - -# clone the repo into a subfolder html, checkout the gh-pages into this folder and commit the freshly generated html -git clone "git@gitlab:${CI_PROJECT_PATH}.git" html -cd html -git checkout gh-pages -rm -f empty.txt -rm -f *.html -rm -f *.js -rm -rf _* -cd .. -# make sure to copy .nojekyll -cp -rf public/.[!.]* public/* html -cd html -git add . - -if git diff-index --quiet HEAD -- -then - exit 0 -fi - -git commit -m"Automatic doc update: ${CI_COMMIT_SHORT_SHA}" -git push \ No newline at end of file diff --git a/ci/set_git_config.sh b/ci/set_git_config.sh deleted file mode 100644 index 860c6aa..0000000 --- a/ci/set_git_config.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -# set shell settings (see https://sipb.mit.edu/doc/safe-shell/) -set -eufv -o pipefail - -# install ssh private key (set as CI variable in GitLab project settings) -mkdir -p ~/.ssh -echo "$SSH_DEPLOY_KEY" > ~/.ssh/id_rsa -chmod 400 ~/.ssh/id_rsa - -# change remote URL to SSH to allow pushing with SSH -git remote set-url --push origin "git@gitlab:${CI_PROJECT_PATH}.git" - -# set git author -git config --global user.name "GitLab-CI" -git config --global user.email "<>" diff --git a/docs/conf.py b/docs/conf.py index 0c12247..1902037 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -4,11 +4,12 @@ # list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html + import os import sys from datetime import datetime -import pkg_resources +import importlib.metadata as metadata import sphinx.ext.autodoc import sensirion_i2c_sen63c @@ -17,16 +18,16 @@ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) # -- Project information ----------------------------------------------------- -distribution = pkg_resources.get_distribution('sensirion_i2c_sen63c') +distribution = metadata.distribution("sensirion_i2c_sen63c") -project = u'sensirion_i2c_sen63c' +project = distribution.name copyright = u'{} Sensirion AG, Switzerland'.format(datetime.now().year) author = 'Sensirion AG' # The short X.Y version -version = sensirion_i2c_sen63c.__version__ +version = distribution.version # The full version, including alpha/beta/rc tags -release = sensirion_i2c_sen63c.__version__ +release = distribution.version # -- General configuration --------------------------------------------------- diff --git a/docs/execute-measurements.rst b/docs/execute-measurements.rst index 17667a5..ae34f91 100644 --- a/docs/execute-measurements.rst +++ b/docs/execute-measurements.rst @@ -26,7 +26,7 @@ execute a simple measurement. python examples/example_usage_sensorbridge_sen63c.py --serial-port -.. _Sensirion SEK-SensorBridge: https://developer.sensirion.com/sensirion-products/sek-sensorbridge/ +.. _Sensirion SEK-SensorBridge: https://developer.sensirion.com/product-support/sek-sensorbridge/ .. _SensorBridge FTDI Driver Installation: https://sensirion.github.io/python-shdlc-sensorbridge/sensor-bridge-installation.html Example script diff --git a/examples/example_usage_linux_sen63c.py b/examples/example_usage_linux_sen63c.py index 979b633..914684b 100644 --- a/examples/example_usage_linux_sen63c.py +++ b/examples/example_usage_linux_sen63c.py @@ -1,13 +1,13 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- # -# (c) Copyright 2025 Sensirion AG, Switzerland +# (c) Copyright 2026 Sensirion AG, Switzerland # # THIS FILE IS AUTOMATICALLY GENERATED! # -# Generator: sensirion-driver-generator 1.1.2 +# Generator: sensirion-driver-generator 1.7.0 # Product: sen63c -# Model-Version: 1.2.0 +# Model-Version: 1.3.0 # import argparse @@ -31,6 +31,7 @@ print(f"serial_number: {serial_number}; " ) sensor.start_continuous_measurement() + time.sleep(1.1) for i in range(100): try: time.sleep(1.0) diff --git a/examples/example_usage_sensorbridge_sen63c.py b/examples/example_usage_sensorbridge_sen63c.py index 988ad11..eb9ba4d 100644 --- a/examples/example_usage_sensorbridge_sen63c.py +++ b/examples/example_usage_sensorbridge_sen63c.py @@ -1,13 +1,13 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- # -# (c) Copyright 2025 Sensirion AG, Switzerland +# (c) Copyright 2026 Sensirion AG, Switzerland # # THIS FILE IS AUTOMATICALLY GENERATED! # -# Generator: sensirion-driver-generator 1.1.2 +# Generator: sensirion-driver-generator 1.7.0 # Product: sen63c -# Model-Version: 1.2.0 +# Model-Version: 1.3.0 # import argparse @@ -40,6 +40,7 @@ print(f"serial_number: {serial_number}; " ) sensor.start_continuous_measurement() + time.sleep(1.1) for i in range(100): try: time.sleep(1.0) diff --git a/images/product-image-sen6x.png b/images/product-image-sen6x.png new file mode 100644 index 0000000..b97bde3 Binary files /dev/null and b/images/product-image-sen6x.png differ diff --git a/images/product-pinout-sen6x.png b/images/product-pinout-sen6x.png new file mode 100644 index 0000000..a940971 Binary files /dev/null and b/images/product-pinout-sen6x.png differ diff --git a/metadata.yml b/metadata.yml index a7e2211..df1c075 100644 --- a/metadata.yml +++ b/metadata.yml @@ -1,7 +1,7 @@ # driver generation metadata -generator_version: 1.1.2 -model_version: 1.2.0 +generator_version: 1.7.0 +model_version: 1.3.0 dg_status: released is_manually_modified: false first_generated: '2025-01-20 12:05' -last_generated: '2025-03-13 10:28' +last_generated: '2026-06-05 09:32' diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..9124f98 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,68 @@ +[build-system] +requires = ["hatchling >= 1.26", "wheel >= 0.45.0"] +build-backend = "hatchling.build" + +[project] +name = "sensirion_i2c_sen63c" +description = "I2C driver for the Sensirion SEN63C sensor family" + +readme = "README.md" +version = "1.3.0" + +requires-python = ">=3.8.4,<4.0" + +authors = [ + { name = "Sensirion", email = "info@sensirion.com" }, +] + +license = "BSD-3-Clause" +license-files = ["LICENSE"] + +keywords = [ + "Sensirion SEN63C", + "I2C", + "SEN63C", + ] + +classifiers = [ + "Intended Audience :: Developers", + "Topic :: System :: Hardware :: Hardware Drivers", + "Topic :: Software Development :: Libraries :: Python Modules", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", +] + +dependencies = [ + "sensirion-driver-adapters>=2.3.0,<3.0", + "sensirion-driver-support-types>=1.2.0,<2.0", + "sensirion-i2c-driver>=1.0,<2.0", + "sensirion-shdlc-sensorbridge>=0.1.0,<2.0" + ] + +[project.optional-dependencies] + +docs=[ + "jinja2~=3.1.6", + "sphinx-rtd-theme==3.0.2", + "sphinx>=7.0,<8.0;python_version < '3.11'", + "sphinx==8.2.3;python_version >= '3.11'", + "lazy-object-proxy ~=1.7.1", + "sphinx-autoapi~=3.0.0", +] + +test= [ + "flake8>=7.1.0", + "mock~=5.2.0", + "pytest>=8.3.5", + "pytest-cov>=5.0.0", + "mypy~=1.13.0", + "setuptools>=73.2.0" +] + +[project.urls] +Changelog = "https://github.com/Sensirion/python-i2c-sen63c/blob/master/CHANGELOG.md" +Repository = "https://github.com/Sensirion/python-i2c-sen63c" +Documentation = "https://sensirion.github.io/python-i2c-sen63c" + diff --git a/sensirion_i2c_sen63c/commands.py b/sensirion_i2c_sen63c/commands.py index f13d9f2..d3b5ec6 100644 --- a/sensirion_i2c_sen63c/commands.py +++ b/sensirion_i2c_sen63c/commands.py @@ -1,13 +1,13 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- # -# (c) Copyright 2025 Sensirion AG, Switzerland +# (c) Copyright 2026 Sensirion AG, Switzerland # # THIS FILE IS AUTOMATICALLY GENERATED! # -# Generator: sensirion-driver-generator 1.1.2 +# Generator: sensirion-driver-generator 1.7.0 # Product: sen63c -# Model-Version: 1.2.0 +# Model-Version: 1.3.0 # """ The transfer classes specify the data that is transferred between host and sensor. The generated transfer classes @@ -24,56 +24,63 @@ class DeviceStatus(BitfieldContainer): fan_error = BitField(offset=4, width=1) reserved2 = BitField(offset=5, width=1) rht_error = BitField(offset=6, width=1) - reserved3 = BitField(offset=7, width=1) - reserved4 = BitField(offset=8, width=1) - reserved5 = BitField(offset=9, width=1) - reserved6 = BitField(offset=10, width=1) + gas_error = BitField(offset=7, width=1) + reserved3 = BitField(offset=8, width=1) + co2_2_error = BitField(offset=9, width=1) + hcho_error = BitField(offset=10, width=1) pm_error = BitField(offset=11, width=1) co2_1_error = BitField(offset=12, width=1) - reserved7 = BitField(offset=13, width=8) + reserved4 = BitField(offset=13, width=8) fan_speed_warning = BitField(offset=21, width=1) + reserved5 = BitField(offset=22, width=10) -class StartContinuousMeasurement(Transfer): +class PerformForcedCo2Recalibration(Transfer): """ - Starts a continuous measurement. - After starting the measurement, it takes some time (~1.1s) until the - first measurement results are available. You could poll with the command - "Get Data Ready" to check when the results are ready to read. - This command is only available in idle mode. If the device is already - in any measure mode, this command has no effect. + Execute the forced recalibration (FRC) of the CO₂. See the datasheet of the + SCD4x sensor for details how the forced recalibration shall be used. """ - CMD_ID = 0x21 + CMD_ID = 0x6707 + + def __init__(self, target_co2_concentration): + self._target_co2_concentration = target_co2_concentration def pack(self): - return self.tx_data.pack([]) + return self.tx_data.pack([self._target_co2_concentration]) - tx = TxData(CMD_ID, '>H', device_busy_delay=0.05, slave_address=None, ignore_ack=False) + tx = TxData(CMD_ID, '>HH', device_busy_delay=0.5, slave_address=None, ignore_ack=False) + rx = RxData('>H') -class StopMeasurement(Transfer): +class PerformCo2SensorFactoryReset(Transfer): """ - Stops the measurement and returns to idle mode. After sending this - command, wait at least 1000 ms before starting a new measurement. - If the device is already in idle mode, this command has no effect. + This command resets all CO₂ sensor configuration settings + stored in the EEPROM and erases the FRC and ASC algorithm + history of the CO₂ sensor. + The configuration settings are CO₂ sensor temperature offset (cannot be + modified over I2C interface), sensor altitude and the ASC + enabled/disabled parameters which are by default stored + in the volatile memory (RAM). + This command is only available in idle mode. """ - CMD_ID = 0x104 + CMD_ID = 0x6754 def pack(self): return self.tx_data.pack([]) - tx = TxData(CMD_ID, '>H', device_busy_delay=1.0, slave_address=None, ignore_ack=False) + tx = TxData(CMD_ID, '>H', device_busy_delay=1.4, slave_address=None, ignore_ack=False) -class GetDataReady(Transfer): +class GetCo2SensorAutomaticSelfCalibration(Transfer): """ - This command can be used to check if new measurement results are ready to read. The data ready flag - is automatically reset after reading the measurement values. + The CO₂ sensor supports automatic self calibration (ASC) for long-term + stability of the CO₂ output. This feature can be enabled or disabled. + By default it is enabled. """ - CMD_ID = 0x202 + CMD_ID = 0x6711 def pack(self): return self.tx_data.pack([]) @@ -82,95 +89,185 @@ def pack(self): rx = RxData('>B?') -class ReadMeasuredValuesAsIntegers(Transfer): +class SetCo2SensorAutomaticSelfCalibration(Transfer): """ - Returns the measured values. - The command "Get Data Ready" can be used to check if new - data is available since the last read operation. If no new data is - available, the previous values will be returned again. If no data - is available at all (e.g. measurement not running for at least one - second), all values will be at their upper limit (0xFFFF for uint16, - 0x7FFF for int16). + Sets the status of the CO₂ sensor automatic self-calibration (ASC). + The CO₂ sensor supports automatic self calibration (ASC) for long-term + stability of the CO₂ output. This feature can be enabled or disabled. + By default it is enabled. """ - CMD_ID = 0x471 + CMD_ID = 0x6711 + + def __init__(self, status): + self._status = status + + def pack(self): + return self.tx_data.pack([self._status]) + + tx = TxData(CMD_ID, '>HH', device_busy_delay=0.02, slave_address=None, ignore_ack=False) + + +class GetAmbientPressure(Transfer): + """ + Gets the ambient pressure value. + The ambient pressure can be used for pressure compensation in the CO₂ + sensor. + """ + + CMD_ID = 0x6720 def pack(self): return self.tx_data.pack([]) tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False) - rx = RxData('>HHHHhhH') + rx = RxData('>H') -class ReadNumberConcentrationValuesAsIntegers(Transfer): +class SetAmbientPressure(Transfer): """ - Returns the measured number concentration values. - The command "Get Data Ready" can be used to check if new - data is available since the last read operation. If no new data is - available, the previous values will be returned again. If no data - is available at all (e.g. measurement not running for at least one - second), all values will be at their upper limit (0xFFFF for uint16). + The ambient pressure can be used for pressure compensation in the CO₂ + sensor. Setting an ambient pressure overrides any pressure compensation + based on a previously set sensor altitude. Use of this command is + recommended for applications experiencing significant ambient pressure + changes to ensure CO₂ sensor accuracy. Valid input values are between + 700 to 1'200 hPa. The default value is 1013 hPa. + This configuration is volatile, i.e. the parameter will be + reverted to its default value after a device restart. """ - CMD_ID = 0x316 + CMD_ID = 0x6720 + + def __init__(self, ambient_pressure): + self._ambient_pressure = ambient_pressure + + def pack(self): + return self.tx_data.pack([self._ambient_pressure]) + + tx = TxData(CMD_ID, '>HH', device_busy_delay=0.02, slave_address=None, ignore_ack=False) + + +class GetSensorAltitude(Transfer): + """ + Gets the current sensor altitude. + The sensor altitude can be used for pressure compensation in the CO₂ + sensor. + """ + + CMD_ID = 0x6736 def pack(self): return self.tx_data.pack([]) tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False) - rx = RxData('>HHHHH') + rx = RxData('>H') -class ReadMeasuredRawValues(Transfer): +class SetSensorAltitude(Transfer): """ - Returns the measured raw values. - The command "Get Data Ready" can be used to check if new - data is available since the last read operation. If no new data is - available, the previous values will be returned again. If no data - is available at all (e.g. measurement not running for at least one - second), all values will be at their upper limit (0xFFFF for uint16, - 0x7FFF for int16). + The sensor altitude can be used for pressure compensation in the CO₂ + sensor. The default sensor altitude value is set to 0 meters above sea + level. Valid input values are between 0 and 3000m. + This configuration is volatile, i.e. the parameter will be + reverted to its default value after a device reset. """ - CMD_ID = 0x492 + CMD_ID = 0x6736 + + def __init__(self, altitude): + self._altitude = altitude + + def pack(self): + return self.tx_data.pack([self._altitude]) + + tx = TxData(CMD_ID, '>HH', device_busy_delay=0.02, slave_address=None, ignore_ack=False) + + +class StartContinuousMeasurement(Transfer): + """ + Starts a continuous measurement. + After starting the measurement, it takes some time (~1.1s) until the + first measurement results are available. You could poll with the command + "Get Data Ready" to check when the results are ready to read. + This command is only available in idle mode. If the device is already + in any measure mode, this command has no effect. + """ + + CMD_ID = 0x21 + + def pack(self): + return self.tx_data.pack([]) + + tx = TxData(CMD_ID, '>H', device_busy_delay=0.05, slave_address=None, ignore_ack=False) + + +class StopMeasurement(Transfer): + """ + Stops the measurement and returns to idle mode. After sending this + command, wait at least 1000 ms before starting a new measurement. + If the device is already in idle mode, this command has no effect. + """ + + CMD_ID = 0x104 + + def pack(self): + return self.tx_data.pack([]) + + tx = TxData(CMD_ID, '>H', device_busy_delay=1.4, slave_address=None, ignore_ack=False) + + +class GetDataReady(Transfer): + """ + This command can be used to check if new measurement results are ready to read. The data ready flag + is automatically reset after reading the measurement values. + """ + + CMD_ID = 0x202 def pack(self): return self.tx_data.pack([]) tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False) - rx = RxData('>hh') + rx = RxData('>B?') -class StartFanCleaning(Transfer): +class ReadNumberConcentrationValuesAsIntegers(Transfer): """ - This command triggers fan cleaning. The fan is set to the maximum - speed for 10 seconds and then automatically stopped. Wait at least 10s - after this command before starting a measurement. + Returns the measured number concentration values. + The command 0x0202 "Get Data Ready" can be used to check if new + data is available since the last read operation. If no new data is + available, the previous values will be returned again. If no data + is available at all (e.g. measurement not running for at least one + second), all values will be at their upper limit (0xFFFF for uint16). """ - CMD_ID = 0x5607 + CMD_ID = 0x316 def pack(self): return self.tx_data.pack([]) tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False) + rx = RxData('>HHHHH') class SetTemperatureOffsetParameters(Transfer): """ This command allows to compensate temperature effects of the design-in at customer side by applying custom temperature offsets - to the ambient temperature. The compensated ambient temperature is - calculated as follows: - T_Ambient_Compensated = T_Ambient + (slope * T_Ambient) + offset - Where slope and offset are the values set with this command, + to the ambient temperature. + + The compensated ambient temperature is calculated as follows: + + * T_Ambient_Compensated = T_Ambient + (slope * T_Ambient) + offset + + Where \"slope\" and \"offset\" are the values set with this command, smoothed with the specified time constant. - All temperatures (T_Ambient_Compensated, T_Ambient and offset) + All temperatures (\"T_Ambient_Compensated\", \"T_Ambient\" and \"offset\") are represented in °C. There are 5 temperature offset slots available that all contribute - additively to T_Ambient_Compensated. The default values for + additively to \"T_Ambient_Compensated\". The default values for the temperature offset parameters are all zero, meaning that - T_Ambient_Compensated is equal to T_Ambient by default. + \"T_Ambient_Compensated\" is equal to \"T_Ambient\" by default. The parameters can be changed in any state of the device, i.e. both in idle mode and in measure mode. """ @@ -210,148 +307,137 @@ def pack(self): tx = TxData(CMD_ID, '>HHHHH', device_busy_delay=0.02, slave_address=None, ignore_ack=False) -class PerformForcedCo2Recalibration(Transfer): - """ - Execute the forced recalibration (FRC) of the CO₂. See the datasheet of the - SCD4x sensor for details how the forced recalibration shall be used. +class GetProductType(Transfer): """ + Gets the product type from the device. - CMD_ID = 0x6707 + The following product types are expected: + - SEN62: '00085800' + - SEN63C: '00085700' + - SEN65: '00085200' + - SEN66: '00085300' + - SEN68: '00085400' + - SEN69C: '00085900' + """ - def __init__(self, target_co2_concentration): - self._target_co2_concentration = target_co2_concentration + CMD_ID = 0xd002 def pack(self): - return self.tx_data.pack([self._target_co2_concentration]) + return self.tx_data.pack([]) - tx = TxData(CMD_ID, '>HH', device_busy_delay=0.5, slave_address=None, ignore_ack=False) - rx = RxData('>H') + tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False) + rx = RxData('>32s') -class SetCo2SensorAutomaticSelfCalibration(Transfer): - """ - Sets the status of the CO₂ sensor automatic self-calibration (ASC). - The CO₂ sensor supports automatic self calibration (ASC) for long-term - stability of the CO₂ output. This feature can be enabled or disabled. - By default it is enabled. - This configuration is volatile, i.e. the parameter will be - reverted to its default value after a device restart. - """ - - CMD_ID = 0x6711 +class GetProductName(Transfer): + """Gets the product name from the device.""" - def __init__(self, status): - self._status = status + CMD_ID = 0xd014 def pack(self): - return self.tx_data.pack([self._status]) + return self.tx_data.pack([]) - tx = TxData(CMD_ID, '>HH', device_busy_delay=0.02, slave_address=None, ignore_ack=False) + tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False) + rx = RxData('>32s') -class GetCo2SensorAutomaticSelfCalibration(Transfer): - """ - The CO₂ sensor supports automatic self calibration (ASC) for long-term - stability of the CO₂ output. This feature can be enabled or disabled. - By default it is enabled. - This configuration is volatile, i.e. the parameter will be - reverted to its default value after a device restart. - """ +class GetSerialNumber(Transfer): + """Gets the serial number from the device.""" - CMD_ID = 0x6711 + CMD_ID = 0xd033 def pack(self): return self.tx_data.pack([]) tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False) - rx = RxData('>B?') + rx = RxData('>32s') -class SetAmbientPressure(Transfer): +class ReadDeviceStatus(Transfer): """ - The ambient pressure can be used for pressure compensation in the CO₂ - sensor. Setting an ambient pressure overrides any pressure compensation - based on a previously set sensor altitude. Use of this command is - recommended for applications experiencing significant ambient pressure - changes to ensure CO₂ sensor accuracy. Valid input values are between - 700 to 1'200 hPa. The default value is 1013 hPa. - This configuration is volatile, i.e. the parameter will be - reverted to its default value after a device restart. + Reads the current device status. + Use this command to get detailed information about the device status. + The device status is encoded in flags. Each device status flag + represents a single bit in a 32-bit integer value. If more than one + error is present, the device status register value is the sum of the + corresponding flag values. For details about the available flags, + refer to the device status flags documentation in the data sheet. """ - CMD_ID = 0x6720 - - def __init__(self, ambient_pressure): - self._ambient_pressure = ambient_pressure + CMD_ID = 0xd206 def pack(self): - return self.tx_data.pack([self._ambient_pressure]) + return self.tx_data.pack([]) - tx = TxData(CMD_ID, '>HH', device_busy_delay=0.02, slave_address=None, ignore_ack=False) + tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False) + rx = RxData('>I') -class GetAmbientPressure(Transfer): +class ReadAndClearDeviceStatus(Transfer): """ - Gets the ambient pressure value. - The ambient pressure can be used for pressure compensation in the CO₂ - sensor. + Reads the current device status (like command 0xD206 "Read Device Status") and afterwards clears + all flags. """ - CMD_ID = 0x6720 + CMD_ID = 0xd210 def pack(self): return self.tx_data.pack([]) tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False) - rx = RxData('>H') + rx = RxData('>I') -class SetSensorAltitude(Transfer): - """ - The sensor altitude can be used for pressure compensation in the CO₂ - sensor. The default sensor altitude value is set to 0 meters above sea - level. Valid input values are between 0 and 3000m. - This configuration is volatile, i.e. the parameter will be - reverted to its default value after a device reset. - """ +class GetVersion(Transfer): + """Gets the version information for the firmware.""" - CMD_ID = 0x6736 + CMD_ID = 0xd100 - def __init__(self, altitude): - self._altitude = altitude + def pack(self): + return self.tx_data.pack([]) + + tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False) + rx = RxData('>BB') + + +class DeviceReset(Transfer): + """Executes a reset on the device. This has the same effect as a power cycle.""" + + CMD_ID = 0xd304 def pack(self): - return self.tx_data.pack([self._altitude]) + return self.tx_data.pack([]) - tx = TxData(CMD_ID, '>HH', device_busy_delay=0.02, slave_address=None, ignore_ack=False) + tx = TxData(CMD_ID, '>H', device_busy_delay=1.2, slave_address=None, ignore_ack=False) -class GetSensorAltitude(Transfer): +class StartFanCleaning(Transfer): """ - Gets the current sensor altitude. - The sensor altitude can be used for pressure compensation in the CO₂ - sensor. + This command triggers fan cleaning. The fan is set to the maximum + speed for 10 seconds and then automatically stopped. Wait at least 10s + after this command before starting a measurement. """ - CMD_ID = 0x6736 + CMD_ID = 0x5607 def pack(self): return self.tx_data.pack([]) tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False) - rx = RxData('>H') class ActivateShtHeater(Transfer): """ + Activate the heater feature of the SHT4x sensor. This command allows to use the inbuilt heater in SHT sensor - to reverse creep at high humidity. + to decontaminate and reverse creep at high humidity. This command activates the SHT sensor heater with 200mW for 1s. - The heater is then automatically deactivated again. - The "get_sht_heater_measurements" command can be used to check if the - heater has finished. - Wait at least 20s after this command before starting a measurement to get - coherent temperature values (heating consequence to disappear). + The SHT heater measurement done just before deactivation can be + read using the command \"Get SHT Heater Measurements\" after + the duration of the heating feature as specified in the SHT4x + datasheet. + Wait at least 20s after this command before starting a measurement + to get coherent temperature values (heating consequence to disappear). """ CMD_ID = 0x6765 @@ -364,9 +450,8 @@ def pack(self): class GetShtHeaterMeasurements(Transfer): """ - Get the measured values when the SHT sensor heating is triggerd. If the - heating is not finished, the returned humidity and temperature values - are 0x7FFF. + Get the measurement values when the SHT sensor heating + is finished. """ CMD_ID = 0x6790 @@ -378,83 +463,40 @@ def pack(self): rx = RxData('>hh') -class GetProductName(Transfer): - """Gets the product name from the device.""" - - CMD_ID = 0xd014 - - def pack(self): - return self.tx_data.pack([]) - - tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False) - rx = RxData('>32s') - - -class GetSerialNumber(Transfer): - """Gets the serial number from the device.""" - - CMD_ID = 0xd033 - - def pack(self): - return self.tx_data.pack([]) - - tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False) - rx = RxData('>32s') - - -class GetVersion(Transfer): - """Gets the version information for the hardware, firmware and communication protocol.""" - - CMD_ID = 0xd100 - - def pack(self): - return self.tx_data.pack([]) - - tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False) - rx = RxData('>BB') - - -class ReadDeviceStatus(Transfer): +class ReadMeasuredValuesAsIntegers(Transfer): """ - Reads the current device status. - Use this command to get detailed information about the device status. - The device status is encoded in flags. Each device status flag - represents a single bit in a 32-bit integer value. If more than one - error is present, the device status register value is the sum of the - corresponding flag values. For details about the available flags, - refer to the device status flags documentation in the data sheet. + Returns the measured values. + The command \"Get Data Ready\" can be used to check if new + data is available since the last read operation. If no new data is + available, the previous values will be returned again. If no data + is available at all (e.g. measurement not running for at least one + second), all values will be at their upper limit (0xFFFF for uint16, + 0x7FFF for int16). """ - CMD_ID = 0xd206 + CMD_ID = 0x471 def pack(self): return self.tx_data.pack([]) tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False) - rx = RxData('>I') + rx = RxData('>HHHHhhh') -class ReadAndClearDeviceStatus(Transfer): +class ReadMeasuredRawValues(Transfer): """ - Reads the current device status (like command 0xD206 "Read Device Status") and afterwards clears - all flags. + Returns the measured raw values. + The command 0x0202 \"Get Data Ready\" can be used to check if new + data is available since the last read operation. If no new data is + available, the previous values will be returned again. If no data + is available at all (e.g. measurement not running for at least one + second), all values will be at their upper limit (0x7FFF for int16). """ - CMD_ID = 0xd210 + CMD_ID = 0x492 def pack(self): return self.tx_data.pack([]) tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False) - rx = RxData('>I') - - -class DeviceReset(Transfer): - """Executes a reset on the device. This has the same effect as a power cycle.""" - - CMD_ID = 0xd304 - - def pack(self): - return self.tx_data.pack([]) - - tx = TxData(CMD_ID, '>H', device_busy_delay=1.2, slave_address=None, ignore_ack=False) + rx = RxData('>hh') diff --git a/sensirion_i2c_sen63c/device.py b/sensirion_i2c_sen63c/device.py index 00189fb..19d0332 100644 --- a/sensirion_i2c_sen63c/device.py +++ b/sensirion_i2c_sen63c/device.py @@ -1,13 +1,13 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- # -# (c) Copyright 2025 Sensirion AG, Switzerland +# (c) Copyright 2026 Sensirion AG, Switzerland # # THIS FILE IS AUTOMATICALLY GENERATED! # -# Generator: sensirion-driver-generator 1.1.2 +# Generator: sensirion-driver-generator 1.7.0 # Product: sen63c -# Model-Version: 1.2.0 +# Model-Version: 1.3.0 # """ The class Sen63cDeviceBase implements the low level interface of the sensor. @@ -19,7 +19,8 @@ from sensirion_driver_support_types.mixin_access import MixinAccess from sensirion_i2c_sen63c.commands import (ActivateShtHeater, DeviceReset, DeviceStatus, GetAmbientPressure, GetCo2SensorAutomaticSelfCalibration, GetDataReady, GetProductName, - GetSensorAltitude, GetSerialNumber, GetShtHeaterMeasurements, GetVersion, + GetProductType, GetSensorAltitude, GetSerialNumber, + GetShtHeaterMeasurements, GetVersion, PerformCo2SensorFactoryReset, PerformForcedCo2Recalibration, ReadAndClearDeviceStatus, ReadDeviceStatus, ReadMeasuredRawValues, ReadMeasuredValuesAsIntegers, ReadNumberConcentrationValuesAsIntegers, SetAmbientPressure, @@ -27,12 +28,7 @@ SetTemperatureAccelerationParameters, SetTemperatureOffsetParameters, StartContinuousMeasurement, StartFanCleaning, StopMeasurement) -from sensirion_i2c_sen63c.result_types import (SignalCo2, SignalHumidity, SignalMassConcentrationPm10p0, - SignalMassConcentrationPm1p0, SignalMassConcentrationPm2p5, - SignalMassConcentrationPm4p0, SignalNumberConcentrationPm0p5, - SignalNumberConcentrationPm10p0, SignalNumberConcentrationPm1p0, - SignalNumberConcentrationPm2p5, SignalNumberConcentrationPm4p0, - SignalTemperature) +from sensirion_i2c_sen63c.result_types import (SignalDividedBy10Uint16, SignalHumidity, SignalTemperature) class Sen63cDeviceBase: @@ -45,6 +41,165 @@ def __init__(self, channel): def channel(self): return self._channel + def perform_forced_co2_recalibration(self, target_co2_concentration): + """ + Execute the forced recalibration (FRC) of the CO₂. See the datasheet of the + SCD4x sensor for details how the forced recalibration shall be used. + + :param target_co2_concentration: + Target CO₂ concentration [ppm] of the test setup. + + :return correction: + Correction value as received from the SCD [ppm CO₂]. + FRC correction [ppm CO₂] is calculated as follows: + FRC = return_value - 0x8000 + If the recalibration has failed this returned value + is 0xFFFF. + + .. note:: + After power-on wait at least 1000 ms and after stopping a measurement 600 ms before sending this + command. This command is not available in measure mode. The recalibration procedure will take about + 500 ms to complete, during which time no other functions can be executed. + This configuration is persistent, i.e. the parameters will be retained during a device reset or power cycle. + """ + transfer = PerformForcedCo2Recalibration(target_co2_concentration) + return execute_transfer(self._channel, transfer)[0] + + def perform_co2_sensor_factory_reset(self): + """ + This command resets all CO₂ sensor configuration settings + stored in the EEPROM and erases the FRC and ASC algorithm + history of the CO₂ sensor. + The configuration settings are CO₂ sensor temperature offset (cannot be + modified over I2C interface), sensor altitude and the ASC + enabled/disabled parameters which are by default stored + in the volatile memory (RAM). + This command is only available in idle mode. + """ + transfer = PerformCo2SensorFactoryReset() + return execute_transfer(self._channel, transfer) + + def get_co2_sensor_automatic_self_calibration(self): + """ + The CO₂ sensor supports automatic self calibration (ASC) for long-term + stability of the CO₂ output. This feature can be enabled or disabled. + By default it is enabled. + + :return padding: + Padding byte, always 0x00. + :return status: + Is set true (0x01) if the automatic self calibration is enabled or false (0x00) if the automatic + self calibration is disabled. + + .. note:: + This command is only available in idle mode. + This configuration is persistent, i.e. the status will be retained during a device reset or power cycle. + """ + transfer = GetCo2SensorAutomaticSelfCalibration() + return execute_transfer(self._channel, transfer) + + def set_co2_sensor_automatic_self_calibration(self, status): + """ + Sets the status of the CO₂ sensor automatic self-calibration (ASC). + The CO₂ sensor supports automatic self calibration (ASC) for long-term + stability of the CO₂ output. This feature can be enabled or disabled. + By default it is enabled. + + :param status: + Set to true (0x0001) to enable or false (0x0000) to disable the automatic CO₂ measurement self + calibration feature. High byte of uint16 is padding and always 0x00. + + .. note:: + This command is only available in idle mode. + This configuration is persistent, i.e. the status will be retained during a device reset or power cycle. + + :Example: + .. code-block:: python + + sensor.set_co2_sensor_automatic_self_calibration(0) + + """ + transfer = SetCo2SensorAutomaticSelfCalibration(status) + return execute_transfer(self._channel, transfer) + + def get_ambient_pressure(self): + """ + Gets the ambient pressure value. + The ambient pressure can be used for pressure compensation in the CO₂ + sensor. + + :return ambient_pressure: + Currently used ambient pressure [hPa] for pressure compensation. + + .. note:: + This command can be used in any state of the device, i.e. both in idle + mode and in measure mode. + """ + transfer = GetAmbientPressure() + return execute_transfer(self._channel, transfer)[0] + + def set_ambient_pressure(self, ambient_pressure): + """ + The ambient pressure can be used for pressure compensation in the CO₂ + sensor. Setting an ambient pressure overrides any pressure compensation + based on a previously set sensor altitude. Use of this command is + recommended for applications experiencing significant ambient pressure + changes to ensure CO₂ sensor accuracy. Valid input values are between + 700 to 1'200 hPa. The default value is 1013 hPa. + This configuration is volatile, i.e. the parameter will be + reverted to its default value after a device restart. + + :param ambient_pressure: + Ambient pressure [hPa] to be used for pressure compensation. + + .. note:: + This command can be used in any state of the device, i.e. both in idle + mode and in measure mode. + + :Example: + .. code-block:: python + + sensor.set_ambient_pressure(1013) + + """ + transfer = SetAmbientPressure(ambient_pressure) + return execute_transfer(self._channel, transfer) + + def get_sensor_altitude(self): + """ + Gets the current sensor altitude. + The sensor altitude can be used for pressure compensation in the CO₂ + sensor. + + :return altitude: + Current sensor altitude [m]. + + .. note:: + This command is only available in idle mode. + """ + transfer = GetSensorAltitude() + return execute_transfer(self._channel, transfer)[0] + + def set_sensor_altitude(self, altitude): + """ + The sensor altitude can be used for pressure compensation in the CO₂ + sensor. The default sensor altitude value is set to 0 meters above sea + level. Valid input values are between 0 and 3000m. + This configuration is volatile, i.e. the parameter will be + reverted to its default value after a device reset. + + :param altitude: + Sensor altitude [m], valid input between 0 and 3000m. + + :Example: + .. code-block:: python + + sensor.set_sensor_altitude(0) + + """ + transfer = SetSensorAltitude(altitude) + return execute_transfer(self._channel, transfer) + def start_continuous_measurement(self): """ Starts a continuous measurement. @@ -80,118 +235,52 @@ def get_data_ready(self): transfer = GetDataReady() return execute_transfer(self._channel, transfer) - def read_measured_values_as_integers(self): - """ - Returns the measured values. - The command "Get Data Ready" can be used to check if new - data is available since the last read operation. If no new data is - available, the previous values will be returned again. If no data - is available at all (e.g. measurement not running for at least one - second), all values will be at their upper limit (0xFFFF for uint16, - 0x7FFF for int16). - - :return mass_concentration_pm1p0: - Value is scaled with factor 10: PM1.0 [µg/m³] = value / 10 - *Note: If this value is unknown, 0xFFFF is returned.* - :return mass_concentration_pm2p5: - Value is scaled with factor 10: PM2.5 [µg/m³] = value / 10 - *Note: If this value is unknown, 0xFFFF is returned.* - :return mass_concentration_pm4p0: - Value is scaled with factor 10: PM4.0 [µg/m³] = value / 10 - *Note: If this value is unknown, 0xFFFF is returned.* - :return mass_concentration_pm10p0: - Value is scaled with factor 10: PM10.0 [µg/m³] = value / 10 - *Note: If this value is unknown, 0xFFFF is returned.* - :return ambient_humidity: - Value is scaled with factor 100: RH [%] = value / 100 - *Note: If this value is unknown, 0x7FFF is returned.* - :return ambient_temperature: - Value is scaled with factor 200: T [°C] = value / 200 - *Note: If this value is unknown, 0x7FFF is returned.* - :return co2: - CO₂ concentration [ppm] - *Note: If this value is unknown, 0xFFFF is returned. During the - first 5..6 seconds after power-on or device reset, this value - will be 0xFFFF as well.* - """ - transfer = ReadMeasuredValuesAsIntegers() - return execute_transfer(self._channel, transfer) - def read_number_concentration_values_as_integers(self): """ Returns the measured number concentration values. - The command "Get Data Ready" can be used to check if new + The command 0x0202 "Get Data Ready" can be used to check if new data is available since the last read operation. If no new data is available, the previous values will be returned again. If no data is available at all (e.g. measurement not running for at least one second), all values will be at their upper limit (0xFFFF for uint16). :return number_concentration_pm0p5: - Value is scaled with factor 10: PM0.5 [particles/cm³] = value / 10 + Value is scaled with factor 10: PM0.5 [particles/cm³] = value / 10. *Note: If this value is unknown, 0xFFFF is returned.* :return number_concentration_pm1p0: - Value is scaled with factor 10: PM1.0 [particles/cm³] = value / 10 + Value is scaled with factor 10: PM1.0 [particles/cm³] = value / 10. *Note: If this value is unknown, 0xFFFF is returned.* :return number_concentration_pm2p5: - Value is scaled with factor 10: PM2.5 [particles/cm³] = value / 10 + Value is scaled with factor 10: PM2.5 [particles/cm³] = value / 10. *Note: If this value is unknown, 0xFFFF is returned.* :return number_concentration_pm4p0: - Value is scaled with factor 10: PM4.0 [particles/cm³] = value / 10 + Value is scaled with factor 10: PM4.0 [particles/cm³] = value / 10. *Note: If this value is unknown, 0xFFFF is returned.* :return number_concentration_pm10p0: - Value is scaled with factor 10: PM10.0 [particles/cm³] = value / 10 - - field: + Value is scaled with factor 10: PM10.0 [particles/cm³] = value / 10. + *Note: If this value is unknown, 0xFFFF is returned.* """ transfer = ReadNumberConcentrationValuesAsIntegers() return execute_transfer(self._channel, transfer) - def read_measured_raw_values(self): - """ - Returns the measured raw values. - The command "Get Data Ready" can be used to check if new - data is available since the last read operation. If no new data is - available, the previous values will be returned again. If no data - is available at all (e.g. measurement not running for at least one - second), all values will be at their upper limit (0xFFFF for uint16, - 0x7FFF for int16). - - :return raw_humidity: - Value is scaled with factor 100: RH [%] = value / 100 - *Note: If this value is unknown, 0x7FFF is returned.* - :return raw_temperature: - Value is scaled with factor 200: T [°C] = value / 200 - *Note: If this value is unknown, 0x7FFF is returned.* - """ - transfer = ReadMeasuredRawValues() - return execute_transfer(self._channel, transfer) - - def start_fan_cleaning(self): - """ - This command triggers fan cleaning. The fan is set to the maximum - speed for 10 seconds and then automatically stopped. Wait at least 10s - after this command before starting a measurement. - - .. note:: - This command is only available in idle mode. - """ - transfer = StartFanCleaning() - return execute_transfer(self._channel, transfer) - def set_temperature_offset_parameters(self, offset, slope, time_constant, slot): """ This command allows to compensate temperature effects of the design-in at customer side by applying custom temperature offsets - to the ambient temperature. The compensated ambient temperature is - calculated as follows: - T_Ambient_Compensated = T_Ambient + (slope * T_Ambient) + offset - Where slope and offset are the values set with this command, + to the ambient temperature. + + The compensated ambient temperature is calculated as follows: + + * T_Ambient_Compensated = T_Ambient + (slope * T_Ambient) + offset + + Where \"slope\" and \"offset\" are the values set with this command, smoothed with the specified time constant. - All temperatures (T_Ambient_Compensated, T_Ambient and offset) + All temperatures (\"T_Ambient_Compensated\", \"T_Ambient\" and \"offset\") are represented in °C. There are 5 temperature offset slots available that all contribute - additively to T_Ambient_Compensated. The default values for + additively to \"T_Ambient_Compensated\". The default values for the temperature offset parameters are all zero, meaning that - T_Ambient_Compensated is equal to T_Ambient by default. + \"T_Ambient_Compensated\" is equal to \"T_Ambient\" by default. The parameters can be changed in any state of the device, i.e. both in idle mode and in measure mode. @@ -249,191 +338,25 @@ def set_temperature_acceleration_parameters(self, k, p, t1, t2): transfer = SetTemperatureAccelerationParameters(k, p, t1, t2) return execute_transfer(self._channel, transfer) - def perform_forced_co2_recalibration(self, target_co2_concentration): - """ - Execute the forced recalibration (FRC) of the CO₂. See the datasheet of the - SCD4x sensor for details how the forced recalibration shall be used. - - :param target_co2_concentration: - Target CO₂ concentration [ppm] of the test setup. - - :return correction: - Correction value as received from the SCD [ppm CO₂]. - FRC correction [ppm CO₂] is calculated as follows: - FRC = return_value - 0x8000 - If the recalibration has failed this returned value - is 0xFFFF. - - .. note:: - After power-on wait at least 1000 ms and after stopping a measurement 600 ms before sending this - command. This command is not available in measure mode. The recalibration procedure will take about - 500 ms to complete, during which time no other functions can be executed. - """ - transfer = PerformForcedCo2Recalibration(target_co2_concentration) - return execute_transfer(self._channel, transfer)[0] - - def set_co2_sensor_automatic_self_calibration(self, status): - """ - Sets the status of the CO₂ sensor automatic self-calibration (ASC). - The CO₂ sensor supports automatic self calibration (ASC) for long-term - stability of the CO₂ output. This feature can be enabled or disabled. - By default it is enabled. - This configuration is volatile, i.e. the parameter will be - reverted to its default value after a device restart. - - :param status: - Set to true (0x0001) to enable or false (0x0000) to disable the automatic CO₂ measurement self - calibration feature. High byte of uint16 is padding and always 0x00. - - .. note:: - This command is only available in idle mode. - - :Example: - .. code-block:: python - - sensor.set_co2_sensor_automatic_self_calibration(0) - - """ - transfer = SetCo2SensorAutomaticSelfCalibration(status) - return execute_transfer(self._channel, transfer) - - def get_co2_sensor_automatic_self_calibration(self): - """ - The CO₂ sensor supports automatic self calibration (ASC) for long-term - stability of the CO₂ output. This feature can be enabled or disabled. - By default it is enabled. - This configuration is volatile, i.e. the parameter will be - reverted to its default value after a device restart. - - :return padding: - Padding byte, always 0x00. - :return status: - Is set true (0x01) if the automatic self calibration is enabled or false (0x00) if the automatic - self calibration is disabled. - - .. note:: - This command is only available in idle mode. - """ - transfer = GetCo2SensorAutomaticSelfCalibration() - return execute_transfer(self._channel, transfer) - - def set_ambient_pressure(self, ambient_pressure): - """ - The ambient pressure can be used for pressure compensation in the CO₂ - sensor. Setting an ambient pressure overrides any pressure compensation - based on a previously set sensor altitude. Use of this command is - recommended for applications experiencing significant ambient pressure - changes to ensure CO₂ sensor accuracy. Valid input values are between - 700 to 1'200 hPa. The default value is 1013 hPa. - This configuration is volatile, i.e. the parameter will be - reverted to its default value after a device restart. - - :param ambient_pressure: - Ambient pressure [hPa] to be used for pressure compensation. - - .. note:: - This command can be used in any state of the device, i.e. both in idle - mode and in measure mode. - - :Example: - .. code-block:: python - - sensor.set_ambient_pressure(1013) - - """ - transfer = SetAmbientPressure(ambient_pressure) - return execute_transfer(self._channel, transfer) - - def get_ambient_pressure(self): + def get_product_type(self): """ - Gets the ambient pressure value. - The ambient pressure can be used for pressure compensation in the CO₂ - sensor. + Gets the product type from the device. - :return ambient_pressure: - Currently used ambient pressure [hPa] for pressure compensation. + The following product types are expected: + - SEN62: '00085800' + - SEN63C: '00085700' + - SEN65: '00085200' + - SEN66: '00085300' + - SEN68: '00085400' + - SEN69C: '00085900' - .. note:: - This command can be used in any state of the device, i.e. both in idle - mode and in measure mode. + :return product_type: + Null-terminated ASCII string containing the product type. + Up to 32 characters can be read from the device. """ - transfer = GetAmbientPressure() + transfer = GetProductType() return execute_transfer(self._channel, transfer)[0] - def set_sensor_altitude(self, altitude): - """ - The sensor altitude can be used for pressure compensation in the CO₂ - sensor. The default sensor altitude value is set to 0 meters above sea - level. Valid input values are between 0 and 3000m. - This configuration is volatile, i.e. the parameter will be - reverted to its default value after a device reset. - - :param altitude: - Sensor altitude [m], valid input between 0 and 3000m. - - :Example: - .. code-block:: python - - sensor.set_sensor_altitude(0) - - """ - transfer = SetSensorAltitude(altitude) - return execute_transfer(self._channel, transfer) - - def get_sensor_altitude(self): - """ - Gets the current sensor altitude. - The sensor altitude can be used for pressure compensation in the CO₂ - sensor. - - :return altitude: - Current sensor altitude [m]. - - .. note:: - This command is only available in idle mode. - """ - transfer = GetSensorAltitude() - return execute_transfer(self._channel, transfer)[0] - - def activate_sht_heater(self): - """ - This command allows to use the inbuilt heater in SHT sensor - to reverse creep at high humidity. - This command activates the SHT sensor heater with 200mW for 1s. - The heater is then automatically deactivated again. - The "get_sht_heater_measurements" command can be used to check if the - heater has finished. - Wait at least 20s after this command before starting a measurement to get - coherent temperature values (heating consequence to disappear). - - .. note:: - This command is only available in idle mode. - """ - transfer = ActivateShtHeater() - return execute_transfer(self._channel, transfer) - - def get_sht_heater_measurements(self): - """ - Get the measured values when the SHT sensor heating is triggerd. If the - heating is not finished, the returned humidity and temperature values - are 0x7FFF. - - :return humidity: - Value is scaled with factor 100: RH [%] = value / 100 - *Note: If this value is not available, 0x7FFF is returned.* - :return temperature: - Value is scaled with factor 200: T [°C] = value / 200 - *Note: If this value is not available, 0x7FFF is returned.* - - .. note:: - This command is only availble in idle mode. - This command must be used after the "activate_sht_heater" command. - The get_sht_heater_measurements command can be queried every 0.05s to get - the measurements. - """ - transfer = GetShtHeaterMeasurements() - return execute_transfer(self._channel, transfer) - def get_product_name(self): """ Gets the product name from the device. @@ -456,18 +379,6 @@ def get_serial_number(self): transfer = GetSerialNumber() return execute_transfer(self._channel, transfer)[0] - def get_version(self): - """ - Gets the version information for the hardware, firmware and communication protocol. - - :return firmware_major: - Firmware major version number. - :return firmware_minor: - Firmware minor version number. - """ - transfer = GetVersion() - return execute_transfer(self._channel, transfer) - def read_device_status(self): """ Reads the current device status. @@ -505,11 +416,133 @@ def read_and_clear_device_status(self): res_0 = execute_transfer(self._channel, transfer)[0] return DeviceStatus(res_0) + def get_version(self): + """ + Gets the version information for the firmware. + + :return firmware_major: + Firmware major version number. + :return firmware_minor: + Firmware minor version number. + """ + transfer = GetVersion() + return execute_transfer(self._channel, transfer) + def device_reset(self): """Executes a reset on the device. This has the same effect as a power cycle.""" transfer = DeviceReset() return execute_transfer(self._channel, transfer) + def start_fan_cleaning(self): + """ + This command triggers fan cleaning. The fan is set to the maximum + speed for 10 seconds and then automatically stopped. Wait at least 10s + after this command before starting a measurement. + + .. note:: + This command is only available in idle mode. + """ + transfer = StartFanCleaning() + return execute_transfer(self._channel, transfer) + + def activate_sht_heater(self): + """ + Activate the heater feature of the SHT4x sensor. + This command allows to use the inbuilt heater in SHT sensor + to decontaminate and reverse creep at high humidity. + This command activates the SHT sensor heater with 200mW for 1s. + The SHT heater measurement done just before deactivation can be + read using the command \"Get SHT Heater Measurements\" after + the duration of the heating feature as specified in the SHT4x + datasheet. + Wait at least 20s after this command before starting a measurement + to get coherent temperature values (heating consequence to disappear). + + .. note:: + This command is only available in idle mode. + """ + transfer = ActivateShtHeater() + return execute_transfer(self._channel, transfer) + + def get_sht_heater_measurements(self): + """ + Get the measurement values when the SHT sensor heating + is finished. + + :return sht_relative_humidity: + If the sht heating is completed, this value indicates + the scaled relative humidity of the SHT4x sensor. + Value is scaled with factor 100: RH [%] = value / 100 + *Note: If this value is not available, 0x7FFF is returned.* + :return sht_temperature: + If the sht heating is completed, this value indicates + the scaled temperature of the SHT4x sensor. + Value is scaled with factor 200: T [°C] = value / 200 + *Note: If this value is not available, 0x7FFF is returned.* + + .. note:: + This command must be used after the \"Activate SHT Heater\" command. The get sht heater measurements + command can be queried every 0.05s to get the measurements. This command is only available in idle + mode. + """ + transfer = GetShtHeaterMeasurements() + return execute_transfer(self._channel, transfer) + + def read_measured_values_as_integers(self): + """ + Returns the measured values. + The command \"Get Data Ready\" can be used to check if new + data is available since the last read operation. If no new data is + available, the previous values will be returned again. If no data + is available at all (e.g. measurement not running for at least one + second), all values will be at their upper limit (0xFFFF for uint16, + 0x7FFF for int16). + + :return mass_concentration_pm1p0: + Value is scaled with factor 10: PM1.0 [µg/m³] = value / 10 + *Note: If this value is unknown, 0xFFFF is returned.* + :return mass_concentration_pm2p5: + Value is scaled with factor 10: PM2.5 [µg/m³] = value / 10 + *Note: If this value is unknown, 0xFFFF is returned.* + :return mass_concentration_pm4p0: + Value is scaled with factor 10: PM4.0 [µg/m³] = value / 10 + *Note: If this value is unknown, 0xFFFF is returned.* + :return mass_concentration_pm10p0: + Value is scaled with factor 10: PM10.0 [µg/m³] = value / 10 + *Note: If this value is unknown, 0xFFFF is returned.* + :return ambient_humidity: + Value is scaled with factor 100: RH [%] = value / 100 + *Note: If this value is unknown, 0x7FFF is returned.* + :return ambient_temperature: + Value is scaled with factor 200: T [°C] = value / 200 + *Note: If this value is unknown, 0x7FFF is returned.* + :return co2: + CO₂ concentration [ppm] + *Note: If this value is unknown, 0x7FFF is returned. During the first + 22..24 seconds starting a measurement, this value will be 0x7FFF.* + """ + transfer = ReadMeasuredValuesAsIntegers() + return execute_transfer(self._channel, transfer) + + def read_measured_raw_values(self): + """ + Returns the measured raw values. + The command 0x0202 \"Get Data Ready\" can be used to check if new + data is available since the last read operation. If no new data is + available, the previous values will be returned again. If no data + is available at all (e.g. measurement not running for at least one + second), all values will be at their upper limit (0x7FFF for int16). + + :return raw_humidity: + Value is scaled with factor 100: RH [%] = value / 100 + *Note: If this value is unknown, 0x7FFF is returned.* + :return raw_temperature: + Value is scaled with factor 200: T [°C] = value / 200 + *Note: If this value is unknown, 0x7FFF is returned.* + """ + transfer = ReadMeasuredRawValues() + return execute_transfer(self._channel, transfer) + class Sen63cDevice(Sen63cDeviceBase): """Driver class implementation of SEN63C""" @@ -535,18 +568,18 @@ def read_measured_values(self): :return humidity: Measured humidity in %RH. :return temperature: - Measured temperature in degrees celsius. + Measured temperature in degrees Celsius. :return co2: - Measured CO2 concentration in ppm. + CO2 concentration in ppm. """ (mass_concentration_pm1p0_raw, mass_concentration_pm2p5_raw, mass_concentration_pm4p0_raw, mass_concentration_pm10p0_raw, humidity_raw, temperature_raw, co2_raw ) = self.read_measured_values_as_integers() - return (SignalMassConcentrationPm1p0(mass_concentration_pm1p0_raw), - SignalMassConcentrationPm2p5(mass_concentration_pm2p5_raw), - SignalMassConcentrationPm4p0(mass_concentration_pm4p0_raw), - SignalMassConcentrationPm10p0(mass_concentration_pm10p0_raw), SignalHumidity(humidity_raw), - SignalTemperature(temperature_raw), SignalCo2(co2_raw)) + return (SignalDividedBy10Uint16(mass_concentration_pm1p0_raw), + SignalDividedBy10Uint16(mass_concentration_pm2p5_raw), + SignalDividedBy10Uint16(mass_concentration_pm4p0_raw), + SignalDividedBy10Uint16(mass_concentration_pm10p0_raw), SignalHumidity(humidity_raw), + SignalTemperature(temperature_raw), co2_raw) def read_number_concentration_values(self): """ @@ -566,8 +599,8 @@ def read_number_concentration_values(self): (number_concentration_pm0p5_raw, number_concentration_pm1p0_raw, number_concentration_pm2p5_raw, number_concentration_pm4p0_raw, number_concentration_pm10p0_raw ) = self.read_number_concentration_values_as_integers() - return (SignalNumberConcentrationPm0p5(number_concentration_pm0p5_raw), - SignalNumberConcentrationPm1p0(number_concentration_pm1p0_raw), - SignalNumberConcentrationPm2p5(number_concentration_pm2p5_raw), - SignalNumberConcentrationPm4p0(number_concentration_pm4p0_raw), - SignalNumberConcentrationPm10p0(number_concentration_pm10p0_raw)) + return (SignalDividedBy10Uint16(number_concentration_pm0p5_raw), + SignalDividedBy10Uint16(number_concentration_pm1p0_raw), + SignalDividedBy10Uint16(number_concentration_pm2p5_raw), + SignalDividedBy10Uint16(number_concentration_pm4p0_raw), + SignalDividedBy10Uint16(number_concentration_pm10p0_raw)) diff --git a/sensirion_i2c_sen63c/response_provider.py b/sensirion_i2c_sen63c/response_provider.py index 119ad8a..700f5b6 100644 --- a/sensirion_i2c_sen63c/response_provider.py +++ b/sensirion_i2c_sen63c/response_provider.py @@ -4,7 +4,8 @@ class Sen63cResponseProvider(rp.ResponseProvider): - RESPONSE_MAP = {0xd014: struct.pack('>32s', rp.random_ascii_string(32)), + RESPONSE_MAP = {0xd002: struct.pack('>32s', rp.random_ascii_string(32)), + 0xd014: struct.pack('>32s', rp.random_ascii_string(32)), 0xd033: struct.pack('>32s', rp.random_ascii_string(32))} def get_id(self) -> str: diff --git a/sensirion_i2c_sen63c/result_types.py b/sensirion_i2c_sen63c/result_types.py index 34faead..284ba50 100644 --- a/sensirion_i2c_sen63c/result_types.py +++ b/sensirion_i2c_sen63c/result_types.py @@ -1,13 +1,13 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- # -# (c) Copyright 2025 Sensirion AG, Switzerland +# (c) Copyright 2026 Sensirion AG, Switzerland # # THIS FILE IS AUTOMATICALLY GENERATED! # -# Generator: sensirion-driver-generator 1.1.2 +# Generator: sensirion-driver-generator 1.7.0 # Product: sen63c -# Model-Version: 1.2.0 +# Model-Version: 1.3.0 # """ The signal classes specify transformations of the raw sensor signals into a meaningful units. @@ -17,134 +17,25 @@ from sensirion_driver_support_types.signals import AbstractSignal -class SignalMassConcentrationPm1p0(AbstractSignal): - """Mass concentration in μg/m³ for particles smaller than 1.0 μm""" +class SignalDividedBy10Uint16(AbstractSignal): + """ + All mass and number concentrations are scaled by a factor 10 to avoid + floating point operations on the communication interface. + """ - def __init__(self, mass_concentration_pm1p0_raw): - self._mass_concentration_pm1p0 = mass_concentration_pm1p0_raw / 10.0 + def __init__(self, scaled_integer_value): + self._divided_by_10_uint16 = scaled_integer_value / 10.0 @property def value(self): - return self._mass_concentration_pm1p0 - - def __str__(self): - return '{0:.2f}'.format(self.value) - - -class SignalMassConcentrationPm2p5(AbstractSignal): - """Mass concentration in μg/m³ for particles smaller than 2.5 μm""" - - def __init__(self, mass_concentration_pm2p5_raw): - self._mass_concentration_pm2p5 = mass_concentration_pm2p5_raw / 10.0 - - @property - def value(self): - return self._mass_concentration_pm2p5 - - def __str__(self): - return '{0:.2f}'.format(self.value) - - -class SignalMassConcentrationPm4p0(AbstractSignal): - """Mass concentration in μg/m³ for particles smaller than 4.0 μm""" - - def __init__(self, mass_concentration_pm4p0_raw): - self._mass_concentration_pm4p0 = mass_concentration_pm4p0_raw / 10.0 - - @property - def value(self): - return self._mass_concentration_pm4p0 - - def __str__(self): - return '{0:.2f}'.format(self.value) - - -class SignalMassConcentrationPm10p0(AbstractSignal): - """Mass concentration in μg/m³ for particles smaller than 10.0 μm""" - - def __init__(self, mass_concentration_pm10p0_raw): - self._mass_concentration_pm10p0 = mass_concentration_pm10p0_raw / 10.0 - - @property - def value(self): - return self._mass_concentration_pm10p0 - - def __str__(self): - return '{0:.2f}'.format(self.value) - - -class SignalNumberConcentrationPm0p5(AbstractSignal): - """Number concentration in particles/cm³ for particles smaller than 0.5 μm""" - - def __init__(self, number_concentration_pm0p5_raw): - self._number_concentration_pm0p5 = number_concentration_pm0p5_raw / 10.0 - - @property - def value(self): - return self._number_concentration_pm0p5 - - def __str__(self): - return '{0:.2f}'.format(self.value) - - -class SignalNumberConcentrationPm1p0(AbstractSignal): - """Number concentration in particles/cm³ for particles smaller than 1.0 μm""" - - def __init__(self, number_concentration_pm1p0_raw): - self._number_concentration_pm1p0 = number_concentration_pm1p0_raw / 10.0 - - @property - def value(self): - return self._number_concentration_pm1p0 - - def __str__(self): - return '{0:.2f}'.format(self.value) - - -class SignalNumberConcentrationPm2p5(AbstractSignal): - """Number concentration in particles/cm³ for particles smaller than 2.5 μm""" - - def __init__(self, number_concentration_pm2p5_raw): - self._number_concentration_pm2p5 = number_concentration_pm2p5_raw / 10.0 - - @property - def value(self): - return self._number_concentration_pm2p5 - - def __str__(self): - return '{0:.2f}'.format(self.value) - - -class SignalNumberConcentrationPm4p0(AbstractSignal): - """Number concentration in particles/cm³ for particles smaller than 4.0 μm""" - - def __init__(self, number_concentration_pm4p0_raw): - self._number_concentration_pm4p0 = number_concentration_pm4p0_raw / 10.0 - - @property - def value(self): - return self._number_concentration_pm4p0 - - def __str__(self): - return '{0:.2f}'.format(self.value) - - -class SignalNumberConcentrationPm10p0(AbstractSignal): - """Number concentration in particles/cm³ for particles smaller than 10.0 μm""" - - def __init__(self, number_concentration_pm10p0_raw): - self._number_concentration_pm10p0 = number_concentration_pm10p0_raw / 10.0 - - @property - def value(self): - return self._number_concentration_pm10p0 + return self._divided_by_10_uint16 def __str__(self): return '{0:.2f}'.format(self.value) class SignalTemperature(AbstractSignal): - """Measured temperature in degrees celsius. The raw value is scaled appropriately.""" + """Measured temperature in degrees Celsius. The raw value is scaled appropriately.""" def __init__(self, temperature_raw): self._temperature = temperature_raw / 200.0 @@ -170,17 +61,3 @@ def value(self): def __str__(self): return '{0:.2f}'.format(self.value) - -class SignalCo2(AbstractSignal): - """Measured CO2 in ppm.""" - - def __init__(self, co2_raw): - self._co2 = co2_raw - - @property - def value(self): - return self._co2 - - def __str__(self): - return '{0}'.format(self.value) - diff --git a/sensirion_i2c_sen63c/version.py b/sensirion_i2c_sen63c/version.py index 338edf5..84aad88 100644 --- a/sensirion_i2c_sen63c/version.py +++ b/sensirion_i2c_sen63c/version.py @@ -1,5 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function +import importlib.metadata as metadata +from typing import Final -version = "0.1.0" +version: Final[str] = metadata.version("sensirion_i2c_sen63c") diff --git a/setup.py b/setup.py index b7e4453..bfae448 100644 --- a/setup.py +++ b/setup.py @@ -1,70 +1,5 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +from setuptools import setup -import os -import re - -from setuptools import setup, find_packages - -# Python versions this package is compatible with -python_requires = '>=3.6, <4' - -# Packages that this package imports. List everything apart from standard lib packages. -install_requires = [ - 'sensirion-i2c-driver>=1.0.0,<2.0', - 'sensirion-driver-adapters>=2.1.9,<3.0', - 'sensirion-driver-support-types~=0.2.0', - 'sensirion-shdlc-sensorbridge>=0.1.0,<0.3.0' -] - -# Packages required for tests and docs -extras_require = { - 'test': [ - 'flake8~=3.7.8', - 'pytest~=6.2.5', - 'pytest-cov~=3.0.0', - ] -} - -# Read version number from version.py -version_line = open("sensirion_i2c_sen63c/version.py", "rt").read() -result = re.search(r"^version = ['\"]([^'\"]*)['\"]", version_line, re.M) -if result: - version_string = result.group(1) -else: - raise RuntimeError("Unable to find version string") - -# Use README.rst and CHANGELOG.md as package description -root_path = os.path.dirname(__file__) -long_description = open(os.path.join(root_path, 'README.md')).read() - -setup( - name='sensirion_i2c_sen63c', - version=version_string, - author='Sensirion', - author_email='info@sensirion.com', - description='I2C driver for the Sensirion SEN63C sensor family', - license='BSD', - keywords="""Sensirion SEN63C - I2C - SEN63C""", - project_urls={ - "Documentation": "https://sensirion.github.io/python-i2c-sen63c", - "Repository": "https://github.com/Sensirion/python-i2c-sen63c", - "Changelog": "https://github.com/Sensirion/python-i2c-sen63c/blob/master/CHANGELOG.md", - }, - packages=find_packages(exclude=['tests', 'tests.*']), - long_description=long_description, - long_description_content_type='text/markdown', - python_requires=python_requires, - install_requires=install_requires, - extras_require=extras_require, - classifiers=[ - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.11', - 'Topic :: Software Development :: Libraries :: Python Modules' - ] -) +setup() \ No newline at end of file diff --git a/tests/test_sen63c.py b/tests/test_sen63c.py index 6c0b035..5bdc3f8 100644 --- a/tests/test_sen63c.py +++ b/tests/test_sen63c.py @@ -1,13 +1,13 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- # -# (c) Copyright 2025 Sensirion AG, Switzerland +# (c) Copyright 2026 Sensirion AG, Switzerland # # THIS FILE IS AUTOMATICALLY GENERATED! # -# Generator: sensirion-driver-generator 1.1.2 +# Generator: sensirion-driver-generator 1.7.0 # Product: sen63c -# Model-Version: 1.2.0 +# Model-Version: 1.3.0 # import pytest @@ -24,9 +24,9 @@ def sensor(channel_provider): yield Sen63cDevice(channel) -def test_perform_forced_co2_recalibration1(sensor): - correction = sensor.perform_forced_co2_recalibration(600) - print(f"correction: {correction}; " +def test_get_product_type1(sensor): + product_type = sensor.get_product_type() + print(f"product_type: {product_type}; " ) @@ -58,30 +58,42 @@ def test_set_temperature_acceleration_parameters1(sensor): sensor.set_temperature_acceleration_parameters(1, 1, 1, 1) -def test_set_co2_sensor_automatic_self_calibration1(sensor): - sensor.set_co2_sensor_automatic_self_calibration(0) +def test_activate_sht_heater1(sensor): + sensor.activate_sht_heater() -def test_get_co2_sensor_automatic_self_calibration1(sensor): - (padding, status - ) = sensor.get_co2_sensor_automatic_self_calibration() - print(f"padding: {padding}; " - f"status: {status}; " +def test_read_device_status1(sensor): + device_status = sensor.read_device_status() + print(f"device_status: {device_status}; " ) -def test_set_ambient_pressure1(sensor): - sensor.set_ambient_pressure(1013) +def test_read_and_clear_device_status1(sensor): + device_status = sensor.read_and_clear_device_status() + print(f"device_status: {device_status}; " + ) -def test_get_ambient_pressure1(sensor): - ambient_pressure = sensor.get_ambient_pressure() - print(f"ambient_pressure: {ambient_pressure}; " +def test_perform_forced_co2_recalibration1(sensor): + correction = sensor.perform_forced_co2_recalibration(600) + print(f"correction: {correction}; " ) -def test_set_sensor_altitude1(sensor): - sensor.set_sensor_altitude(0) +def test_perform_co2_sensor_factory_reset1(sensor): + sensor.perform_co2_sensor_factory_reset() + + +def test_get_co2_sensor_automatic_self_calibration1(sensor): + (padding, status + ) = sensor.get_co2_sensor_automatic_self_calibration() + print(f"padding: {padding}; " + f"status: {status}; " + ) + + +def test_set_co2_sensor_automatic_self_calibration1(sensor): + sensor.set_co2_sensor_automatic_self_calibration(0) def test_get_sensor_altitude1(sensor): @@ -90,20 +102,18 @@ def test_get_sensor_altitude1(sensor): ) -def test_activate_sht_heater1(sensor): - sensor.activate_sht_heater() +def test_set_sensor_altitude1(sensor): + sensor.set_sensor_altitude(0) -def test_read_device_status1(sensor): - device_status = sensor.read_device_status() - print(f"device_status: {device_status}; " +def test_get_ambient_pressure1(sensor): + ambient_pressure = sensor.get_ambient_pressure() + print(f"ambient_pressure: {ambient_pressure}; " ) -def test_read_and_clear_device_status1(sensor): - device_status = sensor.read_and_clear_device_status() - print(f"device_status: {device_status}; " - ) +def test_set_ambient_pressure1(sensor): + sensor.set_ambient_pressure(1013) def test_start_continuous_measurement1(sensor): @@ -159,5 +169,6 @@ def test_start_continuous_measurement1(sensor): f"raw_temperature: {raw_temperature}; " ) sensor.set_temperature_offset_parameters(1, 10, 1, 0) + sensor.set_ambient_pressure(1013) sensor.stop_measurement()