Sensor pinout
-
| *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 a154d77..881091e 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_sen65
@@ -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_sen65')
+distribution = metadata.distribution("sensirion_i2c_sen65")
-project = u'sensirion_i2c_sen65'
+project = distribution.name
copyright = u'{} Sensirion AG, Switzerland'.format(datetime.now().year)
author = 'Sensirion AG'
# The short X.Y version
-version = sensirion_i2c_sen65.__version__
+version = distribution.version
# The full version, including alpha/beta/rc tags
-release = sensirion_i2c_sen65.__version__
+release = distribution.version
# -- General configuration ---------------------------------------------------
diff --git a/docs/execute-measurements.rst b/docs/execute-measurements.rst
index deb86d1..e9b665f 100644
--- a/docs/execute-measurements.rst
+++ b/docs/execute-measurements.rst
@@ -26,7 +26,7 @@ execute a simple measurement.
python examples/example_usage_sensorbridge_sen65.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_sen65.py b/examples/example_usage_linux_sen65.py
index ece4e5c..a4dfb2e 100644
--- a/examples/example_usage_linux_sen65.py
+++ b/examples/example_usage_linux_sen65.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: sen65
-# Model-Version: 1.3.0
+# Model-Version: 1.4.0
#
import argparse
diff --git a/examples/example_usage_sensorbridge_sen65.py b/examples/example_usage_sensorbridge_sen65.py
index 9e72978..dade178 100644
--- a/examples/example_usage_sensorbridge_sen65.py
+++ b/examples/example_usage_sensorbridge_sen65.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: sen65
-# Model-Version: 1.3.0
+# Model-Version: 1.4.0
#
import argparse
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 f5643fb..5e670ff 100644
--- a/metadata.yml
+++ b/metadata.yml
@@ -1,7 +1,7 @@
# driver generation metadata
-generator_version: 1.1.2
-model_version: 1.3.0
+generator_version: 1.7.0
+model_version: 1.4.0
dg_status: released
is_manually_modified: false
first_generated: '2025-02-17 07:46'
-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..2f89f98
--- /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_sen65"
+description = "I2C driver for the Sensirion SEN65 sensor family"
+
+readme = "README.md"
+version = "1.4.0"
+
+requires-python = ">=3.8.4,<4.0"
+
+authors = [
+ { name = "Sensirion", email = "info@sensirion.com" },
+]
+
+license = "BSD-3-Clause"
+license-files = ["LICENSE"]
+
+keywords = [
+ "Sensirion SEN65",
+ "I2C",
+ "SEN65",
+ ]
+
+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-sen65/blob/master/CHANGELOG.md"
+Repository = "https://github.com/Sensirion/python-i2c-sen65"
+Documentation = "https://sensirion.github.io/python-i2c-sen65"
+
diff --git a/sensirion_i2c_sen65/commands.py b/sensirion_i2c_sen65/commands.py
index 3c40b10..91b2b7f 100644
--- a/sensirion_i2c_sen65/commands.py
+++ b/sensirion_i2c_sen65/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: sen65
-# Model-Version: 1.3.0
+# Model-Version: 1.4.0
#
"""
The transfer classes specify the data that is transferred between host and sensor. The generated transfer classes
@@ -26,241 +26,228 @@ class DeviceStatus(BitfieldContainer):
rht_error = BitField(offset=6, width=1)
gas_error = BitField(offset=7, width=1)
reserved3 = BitField(offset=8, width=1)
- reserved4 = BitField(offset=9, width=1)
- reserved5 = BitField(offset=10, width=1)
+ co2_2_error = BitField(offset=9, width=1)
+ hcho_error = BitField(offset=10, width=1)
pm_error = BitField(offset=11, width=1)
- reserved6 = BitField(offset=12, width=1)
- reserved7 = BitField(offset=13, width=8)
+ co2_1_error = BitField(offset=12, width=1)
+ reserved4 = BitField(offset=13, width=8)
fan_speed_warning = BitField(offset=21, width=1)
+ reserved5 = BitField(offset=22, width=10)
-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.
- """
+class GetVocAlgorithmTuningParameters(Transfer):
+ """Gets the parameters to customize the VOC algorithm."""
- CMD_ID = 0x21
+ CMD_ID = 0x60d0
def pack(self):
return self.tx_data.pack([])
- tx = TxData(CMD_ID, '>H', device_busy_delay=0.05, slave_address=None, ignore_ack=False)
+ tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False)
+ rx = RxData('>hhhhhh')
-class StopMeasurement(Transfer):
+class SetVocAlgorithmTuningParameters(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.
+ Sets the parameters to customize the VOC algorithm.
+ This configuration is volatile, i.e. the parameters will be
+ reverted to their default values after a device reset.
"""
- CMD_ID = 0x104
+ CMD_ID = 0x60d0
+
+ def __init__(self, index_offset, learning_time_offset_hours, learning_time_gain_hours, gating_max_duration_minutes,
+ std_initial, gain_factor):
+ self._index_offset = index_offset
+ self._learning_time_offset_hours = learning_time_offset_hours
+ self._learning_time_gain_hours = learning_time_gain_hours
+ self._gating_max_duration_minutes = gating_max_duration_minutes
+ self._std_initial = std_initial
+ self._gain_factor = gain_factor
def pack(self):
- return self.tx_data.pack([])
+ return self.tx_data.pack([self._index_offset, self._learning_time_offset_hours, self._learning_time_gain_hours,
+ self._gating_max_duration_minutes, self._std_initial, self._gain_factor])
- tx = TxData(CMD_ID, '>H', device_busy_delay=1.0, slave_address=None, ignore_ack=False)
+ tx = TxData(CMD_ID, '>Hhhhhhh', device_busy_delay=0.02, slave_address=None, ignore_ack=False)
-class GetDataReady(Transfer):
+class GetVocAlgorithmState(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.
+ Gets the current VOC algorithm state.
+ Allows to backup and restore the VOC algorithm state to resume operation after a power cycle or
+ device reset, skipping initial learning phase. By default, the VOC Engine is reset and the algorithm
+ state is retained if a measurement is stopped and started again. If the VOC algorithm
+ state shall be reset, a device reset or a power cycle can be executed.
"""
- CMD_ID = 0x202
+ CMD_ID = 0x6181
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('>8B')
-class ReadMeasuredValuesAsIntegers(Transfer):
+class SetVocAlgorithmState(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 VOC algorithm state previously received with "Get VOC Algorithm State" command.
+ Allows restoration of the VOC algorithm state to resume operation after a power cycle or device
+ reset, skipping initial learning phase. By default, the VOC Engine is reset, and the algorithm state is retained if
+ a measurement is stopped and started again. If the VOC algorithm state shall be reset, a device reset, or a
+ power cycle can be executed.
"""
- CMD_ID = 0x446
+ CMD_ID = 0x6181
+
+ def __init__(self, state):
+ self._state = state
def pack(self):
- return self.tx_data.pack([])
+ return self.tx_data.pack([self._state])
- tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False)
- rx = RxData('>HHHHhhhh')
+ tx = TxData(CMD_ID, '>H8B')
-class ReadNumberConcentrationValuesAsIntegers(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).
- """
+class GetNoxAlgorithmTuningParameters(Transfer):
+ """Gets the parameters to customize the NOx algorithm."""
- CMD_ID = 0x316
+ CMD_ID = 0x60e1
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('>hhhhhh')
-class ReadMeasuredRawValues(Transfer):
+class SetNoxAlgorithmTuningParameters(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).
+ Sets the parameters to customize the NOx algorithm.
+ This configuration is volatile, i.e. the parameters will be
+ reverted to their default values after a device reset.
"""
- CMD_ID = 0x455
+ CMD_ID = 0x60e1
+
+ def __init__(self, index_offset, learning_time_offset_hours, learning_time_gain_hours, gating_max_duration_minutes,
+ std_initial, gain_factor):
+ self._index_offset = index_offset
+ self._learning_time_offset_hours = learning_time_offset_hours
+ self._learning_time_gain_hours = learning_time_gain_hours
+ self._gating_max_duration_minutes = gating_max_duration_minutes
+ self._std_initial = std_initial
+ self._gain_factor = gain_factor
def pack(self):
- return self.tx_data.pack([])
+ return self.tx_data.pack([self._index_offset, self._learning_time_offset_hours, self._learning_time_gain_hours,
+ self._gating_max_duration_minutes, self._std_initial, self._gain_factor])
- tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False)
- rx = RxData('>hhHH')
+ tx = TxData(CMD_ID, '>Hhhhhhh', device_busy_delay=0.02, slave_address=None, ignore_ack=False)
-class StartFanCleaning(Transfer):
+class StartContinuousMeasurement(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.
+ 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 = 0x5607
+ CMD_ID = 0x21
def pack(self):
return self.tx_data.pack([])
- tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False)
+ tx = TxData(CMD_ID, '>H', device_busy_delay=0.05, slave_address=None, ignore_ack=False)
-class SetTemperatureOffsetParameters(Transfer):
+class StopMeasurement(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,
- smoothed with the specified time constant.
- 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
- the temperature offset parameters are all zero, meaning that
- 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.
+ 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 = 0x60b2
-
- def __init__(self, offset, slope, time_constant, slot):
- self._offset = offset
- self._slope = slope
- self._time_constant = time_constant
- self._slot = slot
+ CMD_ID = 0x104
def pack(self):
- return self.tx_data.pack([self._offset, self._slope, self._time_constant, self._slot])
+ return self.tx_data.pack([])
- tx = TxData(CMD_ID, '>HhhHH', device_busy_delay=0.02, slave_address=None, ignore_ack=False)
+ tx = TxData(CMD_ID, '>H', device_busy_delay=1.4, slave_address=None, ignore_ack=False)
-class SetVocAlgorithmTuningParameters(Transfer):
+class GetDataReady(Transfer):
"""
- Sets the parameters to customize the VOC algorithm.
- This configuration is volatile, i.e. the parameters will be
- reverted to their default values after a device reset.
+ 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 = 0x60d0
-
- def __init__(self, index_offset, learning_time_offset_hours, learning_time_gain_hours, gating_max_duration_minutes,
- std_initial, gain_factor):
- self._index_offset = index_offset
- self._learning_time_offset_hours = learning_time_offset_hours
- self._learning_time_gain_hours = learning_time_gain_hours
- self._gating_max_duration_minutes = gating_max_duration_minutes
- self._std_initial = std_initial
- self._gain_factor = gain_factor
+ CMD_ID = 0x202
def pack(self):
- return self.tx_data.pack([self._index_offset, self._learning_time_offset_hours, self._learning_time_gain_hours,
- self._gating_max_duration_minutes, self._std_initial, self._gain_factor])
+ return self.tx_data.pack([])
- tx = TxData(CMD_ID, '>Hhhhhhh', 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('>B?')
-class GetVocAlgorithmTuningParameters(Transfer):
- """Gets the parameters to customize the VOC algorithm."""
+class ReadNumberConcentrationValuesAsIntegers(Transfer):
+ """
+ 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 = 0x60d0
+ 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('>hhhhhh')
+ rx = RxData('>HHHHH')
-class SetNoxAlgorithmTuningParameters(Transfer):
- """
- Sets the parameters to customize the NOx algorithm.
- This configuration is volatile, i.e. the parameters will be
- reverted to their default values after a device reset.
+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.
- CMD_ID = 0x60e1
-
- def __init__(self, index_offset, learning_time_offset_hours, learning_time_gain_hours, gating_max_duration_minutes,
- std_initial, gain_factor):
- self._index_offset = index_offset
- self._learning_time_offset_hours = learning_time_offset_hours
- self._learning_time_gain_hours = learning_time_gain_hours
- self._gating_max_duration_minutes = gating_max_duration_minutes
- self._std_initial = std_initial
- self._gain_factor = gain_factor
-
- def pack(self):
- return self.tx_data.pack([self._index_offset, self._learning_time_offset_hours, self._learning_time_gain_hours,
- self._gating_max_duration_minutes, self._std_initial, self._gain_factor])
+ The compensated ambient temperature is calculated as follows:
- tx = TxData(CMD_ID, '>Hhhhhhh', device_busy_delay=0.02, slave_address=None, ignore_ack=False)
+ * 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\")
+ are represented in °C.
+ There are 5 temperature offset slots available that all contribute
+ 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.
+ The parameters can be changed in any state of the device, i.e. both in
+ idle mode and in measure mode.
+ """
-class GetNoxAlgorithmTuningParameters(Transfer):
- """Gets the parameters to customize the NOx algorithm."""
+ CMD_ID = 0x60b2
- CMD_ID = 0x60e1
+ def __init__(self, offset, slope, time_constant, slot):
+ self._offset = offset
+ self._slope = slope
+ self._time_constant = time_constant
+ self._slot = slot
def pack(self):
- return self.tx_data.pack([])
+ return self.tx_data.pack([self._offset, self._slope, self._time_constant, self._slot])
- tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False)
- rx = RxData('>hhhhhh')
+ tx = TxData(CMD_ID, '>HhhHH', device_busy_delay=0.02, slave_address=None, ignore_ack=False)
class SetTemperatureAccelerationParameters(Transfer):
@@ -284,157 +271,197 @@ def pack(self):
tx = TxData(CMD_ID, '>HHHHH', device_busy_delay=0.02, slave_address=None, ignore_ack=False)
-class SetVocAlgorithmState(Transfer):
+class GetProductType(Transfer):
"""
- Sets the VOC algorithm state previously received with "Get VOC Algorithm State" command.
- Allows restoration of the VOC algorithm state to resume operation after a power cycle or device
- reset, skipping initial learning phase. By default, the VOC Engine is reset, and the algorithm state is retained if
- a measurement is stopped and started again. If the VOC algorithm state shall be reset, a device reset, or a
- power cycle can be executed.
+ Gets the product type from the device.
+
+ The following product types are expected:
+ - SEN62: '00085800'
+ - SEN63C: '00085700'
+ - SEN65: '00085200'
+ - SEN66: '00085300'
+ - SEN68: '00085400'
+ - SEN69C: '00085900'
"""
- CMD_ID = 0x6181
+ CMD_ID = 0xd002
- def __init__(self, state):
- self._state = state
+ 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 GetProductName(Transfer):
+ """Gets the product name from the device."""
+
+ CMD_ID = 0xd014
def pack(self):
- return self.tx_data.pack([self._state])
+ return self.tx_data.pack([])
- tx = TxData(CMD_ID, '>H8B')
+ tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False)
+ rx = RxData('>32s')
-class GetVocAlgorithmState(Transfer):
- """
- Gets the current VOC algorithm state.
- Allows to backup and restore the VOC algorithm state to resume operation after a power cycle or
- device reset, skipping initial learning phase. By default, the VOC Engine is reset and the algorithm
- state is retained if a measurement is stopped and started again. If the VOC algorithm
- state shall be reset, a device reset or a power cycle can be executed.
- """
+class GetSerialNumber(Transfer):
+ """Gets the serial number from the device."""
- CMD_ID = 0x6181
+ 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('>8B')
+ rx = RxData('>32s')
-class ActivateShtHeater(Transfer):
+class ReadDeviceStatus(Transfer):
"""
- 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).
+ 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 = 0x6765
+ CMD_ID = 0xd206
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 GetShtHeaterMeasurements(Transfer):
+class ReadAndClearDeviceStatus(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.
+ Reads the current device status (like command 0xD206 "Read Device Status") and afterwards clears
+ all flags.
"""
- CMD_ID = 0x6790
+ 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('>hh')
+ rx = RxData('>I')
-class GetProductName(Transfer):
- """Gets the product name from the device."""
+class GetVersion(Transfer):
+ """Gets the version information for the firmware."""
- CMD_ID = 0xd014
+ 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('>32s')
+ rx = RxData('>BB')
-class GetSerialNumber(Transfer):
- """Gets the serial number from the device."""
+class DeviceReset(Transfer):
+ """Executes a reset on the device. This has the same effect as a power cycle."""
- CMD_ID = 0xd033
+ 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)
+
+
+class StartFanCleaning(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.
+ """
+
+ 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('>32s')
-class GetVersion(Transfer):
- """Gets the version information for the hardware, firmware and communication protocol."""
+class ActivateShtHeater(Transfer):
+ """
+ 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).
+ """
- CMD_ID = 0xd100
+ CMD_ID = 0x6765
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 GetShtHeaterMeasurements(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.
+ Get the measurement values when the SHT sensor heating
+ is finished.
"""
- CMD_ID = 0xd206
+ CMD_ID = 0x6790
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('>hh')
-class ReadAndClearDeviceStatus(Transfer):
+class ReadMeasuredValuesAsIntegers(Transfer):
"""
- Reads the current device status (like command 0xD206 "Read Device Status") and afterwards clears
- all flags.
+ 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 = 0xd210
+ CMD_ID = 0x446
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('>HHHHhhhh')
-class DeviceReset(Transfer):
- """Executes a reset on the device. This has the same effect as a power cycle."""
+class ReadMeasuredRawValues(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).
+ """
- CMD_ID = 0xd304
+ CMD_ID = 0x455
def pack(self):
return self.tx_data.pack([])
- tx = TxData(CMD_ID, '>H', device_busy_delay=1.2, slave_address=None, ignore_ack=False)
+ tx = TxData(CMD_ID, '>H', device_busy_delay=0.02, slave_address=None, ignore_ack=False)
+ rx = RxData('>hhHH')
diff --git a/sensirion_i2c_sen65/device.py b/sensirion_i2c_sen65/device.py
index e959db1..b7ff22d 100644
--- a/sensirion_i2c_sen65/device.py
+++ b/sensirion_i2c_sen65/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: sen65
-# Model-Version: 1.3.0
+# Model-Version: 1.4.0
#
"""
The class Sen65DeviceBase implements the low level interface of the sensor.
@@ -18,8 +18,8 @@
from sensirion_driver_adapters.transfer import execute_transfer
from sensirion_driver_support_types.mixin_access import MixinAccess
from sensirion_i2c_sen65.commands import (ActivateShtHeater, DeviceReset, DeviceStatus, GetDataReady,
- GetNoxAlgorithmTuningParameters, GetProductName, GetSerialNumber,
- GetShtHeaterMeasurements, GetVersion, GetVocAlgorithmState,
+ GetNoxAlgorithmTuningParameters, GetProductName, GetProductType,
+ GetSerialNumber, GetShtHeaterMeasurements, GetVersion, GetVocAlgorithmState,
GetVocAlgorithmTuningParameters, ReadAndClearDeviceStatus, ReadDeviceStatus,
ReadMeasuredRawValues, ReadMeasuredValuesAsIntegers,
ReadNumberConcentrationValuesAsIntegers, SetNoxAlgorithmTuningParameters,
@@ -27,12 +27,8 @@
SetVocAlgorithmState, SetVocAlgorithmTuningParameters,
StartContinuousMeasurement, StartFanCleaning, StopMeasurement)
-from sensirion_i2c_sen65.result_types import (SignalHumidity, SignalMassConcentrationPm10p0,
- SignalMassConcentrationPm1p0, SignalMassConcentrationPm2p5,
- SignalMassConcentrationPm4p0, SignalNoxIndex,
- SignalNumberConcentrationPm0p5, SignalNumberConcentrationPm10p0,
- SignalNumberConcentrationPm1p0, SignalNumberConcentrationPm2p5,
- SignalNumberConcentrationPm4p0, SignalTemperature, SignalVocIndex)
+from sensirion_i2c_sen65.result_types import (SignalDividedBy10Int16, SignalDividedBy10Uint16, SignalHumidity,
+ SignalTemperature)
class Sen65DeviceBase:
@@ -45,192 +41,31 @@ def __init__(self, channel):
def channel(self):
return self._channel
- def start_continuous_measurement(self):
- """
- 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.
- """
- transfer = StartContinuousMeasurement()
- return execute_transfer(self._channel, transfer)
-
- def stop_measurement(self):
- """
- 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.
- """
- transfer = StopMeasurement()
- return execute_transfer(self._channel, transfer)
-
- def get_data_ready(self):
- """
- 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.
-
- :return padding:
- Padding byte, always 0x00.
- :return data_ready:
- True (0x01) if data is ready, False (0x00) if not. When no measurement is running, False will be
- returned.
- """
- 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 voc_index:
- Value is scaled with factor 10: VOC Index = value / 10
- *Note: If this value is unknown, 0x7FFF is returned.*
- :return nox_index:
- Value is scaled with factor 10: NOx Index = value / 10
- *Note: If this value is unknown, 0x7FFF is returned. During
- the first 10..11 seconds after power-on or device reset, this
- value will be 0x7FFF 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
- 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
- *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
- *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
- *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
- *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
- *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.*
- :return raw_voc:
- Raw measured VOC ticks without scale factor.
- *Note: If this value is unknown, 0xFFFF is returned.*
- :return raw_nox:
- Raw measured NOx ticks without scale factor.
- *Note: If this value is unknown, 0xFFFF is returned. During
- the first 10..11 seconds after power-on or device reset, this
- value will be 0xFFFF as well.*
+ def get_voc_algorithm_tuning_parameters(self):
"""
- transfer = ReadMeasuredRawValues()
- return execute_transfer(self._channel, transfer)
+ Gets the parameters to customize the VOC algorithm.
- 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.
+ :return index_offset:
+ VOC index representing typical (average) conditions.
+ :return learning_time_offset_hours:
+ Time constant to estimate the VOC algorithm offset from the history in hours. Past events will be
+ forgotten after about twice the learning time.
+ :return learning_time_gain_hours:
+ Time constant to estimate the VOC algorithm gain from the history in hours. Past events will be
+ forgotten after about twice the learning time.
+ :return gating_max_duration_minutes:
+ Maximum duration of gating in minutes (freeze of estimator during high VOC index signal). Zero
+ disables the gating.
+ :return std_initial:
+ Initial estimate for standard deviation. Lower value boosts events during initial learning period,
+ but may result in larger device-to-device variations.
+ :return gain_factor:
+ Gain factor to amplify or to attenuate the VOC index output.
.. 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,
- smoothed with the specified time constant.
- 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
- the temperature offset parameters are all zero, meaning that
- 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.
-
- :param offset:
- Constant temperature offset scaled with factor 200 (T [°C] = value / 200).
- :param slope:
- Normalized temperature offset slope scaled with factor 10000 (applied factor = value / 10000).
- :param time_constant:
- The time constant determines how fast the new slope and offset will be applied.
- After the specified value in seconds, 63% of the new slope and offset are applied.
- A time constant of zero means the new values will be applied immediately
- (within the next measure interval of 1 second).
- :param slot:
- The temperature offset slot to be modified.
- Valid values are 0 .. 4. If the value is outside this range,
- the parameters will not be applied.
-
- .. note::
- This configuration is volatile, i.e. the parameters will be reverted to their default value of zero
- after a device reset.
-
- :Example:
- .. code-block:: python
-
- sensor.set_temperature_offset_parameters(1, 10, 1, 0)
-
- """
- transfer = SetTemperatureOffsetParameters(offset, slope, time_constant, slot)
+ transfer = GetVocAlgorithmTuningParameters()
return execute_transfer(self._channel, transfer)
def set_voc_algorithm_tuning_parameters(self, index_offset, learning_time_offset_hours, learning_time_gain_hours,
@@ -276,31 +111,68 @@ def set_voc_algorithm_tuning_parameters(self, index_offset, learning_time_offset
gating_max_duration_minutes, std_initial, gain_factor)
return execute_transfer(self._channel, transfer)
- def get_voc_algorithm_tuning_parameters(self):
+ def get_voc_algorithm_state(self):
"""
- Gets the parameters to customize the VOC algorithm.
+ Gets the current VOC algorithm state.
+ Allows to backup and restore the VOC algorithm state to resume operation after a power cycle or
+ device reset, skipping initial learning phase. By default, the VOC Engine is reset and the algorithm
+ state is retained if a measurement is stopped and started again. If the VOC algorithm
+ state shall be reset, a device reset or a power cycle can be executed.
+
+ :return state:
+ Current VOC algorithm state.
+
+ .. note::
+ This command can be used either in measure mode or in idle mode (which will then return the state at the
+ time when the measurement was stopped). In measure mode, the state can be read each measure interval to
+ always have the latest state available, even in case of a sudden power loss.
+ """
+ transfer = GetVocAlgorithmState()
+ return execute_transfer(self._channel, transfer)[0]
+
+ def set_voc_algorithm_state(self, state):
+ """
+ Sets the VOC algorithm state previously received with "Get VOC Algorithm State" command.
+ Allows restoration of the VOC algorithm state to resume operation after a power cycle or device
+ reset, skipping initial learning phase. By default, the VOC Engine is reset, and the algorithm state is retained if
+ a measurement is stopped and started again. If the VOC algorithm state shall be reset, a device reset, or a
+ power cycle can be executed.
+
+ :param state:
+ VOC algorithm state to restore.
+
+ .. note::
+ This command is only available in idle mode and the state will be applied only once when starting
+ the next measurement. In measure mode, this command has no effect.
+ """
+ transfer = SetVocAlgorithmState(state)
+ return execute_transfer(self._channel, transfer)
+
+ def get_nox_algorithm_tuning_parameters(self):
+ """
+ Gets the parameters to customize the NOx algorithm.
:return index_offset:
- VOC index representing typical (average) conditions.
+ NOx index representing typical (average) conditions.
:return learning_time_offset_hours:
- Time constant to estimate the VOC algorithm offset from the history in hours. Past events will be
+ Time constant to estimate the NOx algorithm offset from the history in hours. Past events will be
forgotten after about twice the learning time.
:return learning_time_gain_hours:
- Time constant to estimate the VOC algorithm gain from the history in hours. Past events will be
- forgotten after about twice the learning time.
+ The time constant to estimate the NOx algorithm gain from the history has no impact for NOx. This
+ parameter is still in place for consistency reasons with the VOC tuning parameters command.
:return gating_max_duration_minutes:
- Maximum duration of gating in minutes (freeze of estimator during high VOC index signal). Zero
+ Maximum duration of gating in minutes (freeze of estimator during high NOx index signal). Zero
disables the gating.
:return std_initial:
- Initial estimate for standard deviation. Lower value boosts events during initial learning period,
- but may result in larger device-to-device variations.
+ The initial estimate for standard deviation has no impact for NOx. This parameter is still in place
+ for consistency reasons with the VOC tuning parameters command.
:return gain_factor:
- Gain factor to amplify or to attenuate the VOC index output.
+ Gain factor to amplify or to attenuate the NOx index output.
.. note::
- This command is only available in idle mode.
+ This command is available only in idle mode.
"""
- transfer = GetVocAlgorithmTuningParameters()
+ transfer = GetNoxAlgorithmTuningParameters()
return execute_transfer(self._channel, transfer)
def set_nox_algorithm_tuning_parameters(self, index_offset, learning_time_offset_hours, learning_time_gain_hours,
@@ -346,31 +218,115 @@ def set_nox_algorithm_tuning_parameters(self, index_offset, learning_time_offset
gating_max_duration_minutes, std_initial, gain_factor)
return execute_transfer(self._channel, transfer)
- def get_nox_algorithm_tuning_parameters(self):
+ def start_continuous_measurement(self):
"""
- Gets the parameters to customize the NOx algorithm.
-
- :return index_offset:
- NOx index representing typical (average) conditions.
- :return learning_time_offset_hours:
- Time constant to estimate the NOx algorithm offset from the history in hours. Past events will be
- forgotten after about twice the learning time.
- :return learning_time_gain_hours:
- The time constant to estimate the NOx algorithm gain from the history has no impact for NOx. This
- parameter is still in place for consistency reasons with the VOC tuning parameters command.
- :return gating_max_duration_minutes:
- Maximum duration of gating in minutes (freeze of estimator during high NOx index signal). Zero
- disables the gating.
- :return std_initial:
- The initial estimate for standard deviation has no impact for NOx. This parameter is still in place
- for consistency reasons with the VOC tuning parameters command.
- :return gain_factor:
- Gain factor to amplify or to attenuate the NOx index output.
+ 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.
+ """
+ transfer = StartContinuousMeasurement()
+ return execute_transfer(self._channel, transfer)
+
+ def stop_measurement(self):
+ """
+ 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.
+ """
+ transfer = StopMeasurement()
+ return execute_transfer(self._channel, transfer)
+
+ def get_data_ready(self):
+ """
+ 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.
+
+ :return padding:
+ Padding byte, always 0x00.
+ :return data_ready:
+ True (0x01) if data is ready, False (0x00) if not. When no measurement is running, False will be
+ returned.
+ """
+ transfer = GetDataReady()
+ return execute_transfer(self._channel, transfer)
+
+ def read_number_concentration_values_as_integers(self):
+ """
+ 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).
+
+ :return number_concentration_pm0p5:
+ 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.
+ *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.
+ *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.
+ *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.
+ *Note: If this value is unknown, 0xFFFF is returned.*
+ """
+ transfer = ReadNumberConcentrationValuesAsIntegers()
+ 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,
+ smoothed with the specified time constant.
+ 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
+ the temperature offset parameters are all zero, meaning that
+ \"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.
+
+ :param offset:
+ Constant temperature offset scaled with factor 200 (T [°C] = value / 200).
+ :param slope:
+ Normalized temperature offset slope scaled with factor 10000 (applied factor = value / 10000).
+ :param time_constant:
+ The time constant determines how fast the new slope and offset will be applied.
+ After the specified value in seconds, 63% of the new slope and offset are applied.
+ A time constant of zero means the new values will be applied immediately
+ (within the next measure interval of 1 second).
+ :param slot:
+ The temperature offset slot to be modified.
+ Valid values are 0 .. 4. If the value is outside this range,
+ the parameters will not be applied.
.. note::
- This command is available only in idle mode.
+ This configuration is volatile, i.e. the parameters will be reverted to their default value of zero
+ after a device reset.
+
+ :Example:
+ .. code-block:: python
+
+ sensor.set_temperature_offset_parameters(1, 10, 1, 0)
+
"""
- transfer = GetNoxAlgorithmTuningParameters()
+ transfer = SetTemperatureOffsetParameters(offset, slope, time_constant, slot)
return execute_transfer(self._channel, transfer)
def set_temperature_acceleration_parameters(self, k, p, t1, t2):
@@ -400,82 +356,25 @@ def set_temperature_acceleration_parameters(self, k, p, t1, t2):
transfer = SetTemperatureAccelerationParameters(k, p, t1, t2)
return execute_transfer(self._channel, transfer)
- def set_voc_algorithm_state(self, state):
- """
- Sets the VOC algorithm state previously received with "Get VOC Algorithm State" command.
- Allows restoration of the VOC algorithm state to resume operation after a power cycle or device
- reset, skipping initial learning phase. By default, the VOC Engine is reset, and the algorithm state is retained if
- a measurement is stopped and started again. If the VOC algorithm state shall be reset, a device reset, or a
- power cycle can be executed.
-
- :param state:
- VOC algorithm state to restore.
-
- .. note::
- This command is only available in idle mode and the state will be applied only once when starting
- the next measurement. In measure mode, this command has no effect.
- """
- transfer = SetVocAlgorithmState(state)
- return execute_transfer(self._channel, transfer)
-
- def get_voc_algorithm_state(self):
+ def get_product_type(self):
"""
- Gets the current VOC algorithm state.
- Allows to backup and restore the VOC algorithm state to resume operation after a power cycle or
- device reset, skipping initial learning phase. By default, the VOC Engine is reset and the algorithm
- state is retained if a measurement is stopped and started again. If the VOC algorithm
- state shall be reset, a device reset or a power cycle can be executed.
+ Gets the product type from the device.
- :return state:
- Current VOC algorithm state.
+ The following product types are expected:
+ - SEN62: '00085800'
+ - SEN63C: '00085700'
+ - SEN65: '00085200'
+ - SEN66: '00085300'
+ - SEN68: '00085400'
+ - SEN69C: '00085900'
- .. note::
- This command can be used either in measure mode or in idle mode (which will then return the state at the
- time when the measurement was stopped). In measure mode, the state can be read each measure interval to
- always have the latest state available, even in case of a sudden power loss.
+ :return product_type:
+ Null-terminated ASCII string containing the product type.
+ Up to 32 characters can be read from the device.
"""
- transfer = GetVocAlgorithmState()
+ transfer = GetProductType()
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.
@@ -498,18 +397,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.
@@ -547,11 +434,146 @@ 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 voc_index:
+ Value is scaled with factor 10: VOC Index = value / 10
+ *Note: If this value is unknown, 0x7FFF is returned.*
+ :return nox_index:
+ Value is scaled with factor 10: NOx Index = value / 10
+ *Note: If this value is unknown, 0x7FFF is returned. During
+ the first 10..11 seconds after power-on or device reset, this
+ value will be 0x7FFF as well.*
+ """
+ transfer = ReadMeasuredValuesAsIntegers()
+ 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.*
+ :return raw_voc:
+ Raw measured VOC ticks without scale factor.
+ *Note: If this value is unknown, 0xFFFF is returned.*
+ :return raw_nox:
+ Raw measured NOx ticks without scale factor.
+ *Note: If this value is unknown, 0xFFFF is returned. During
+ the first 10..11 seconds after power-on or device reset, this
+ value will be 0xFFFF as well.*
+ """
+ transfer = ReadMeasuredRawValues()
+ return execute_transfer(self._channel, transfer)
+
class Sen65Device(Sen65DeviceBase):
"""Driver class implementation of SEN65"""
@@ -577,20 +599,21 @@ def read_measured_values(self):
:return humidity:
Measured humidity in %RH.
:return temperature:
- Measured temperature in degrees celsius.
+ Measured temperature in degrees Celsius.
:return voc_index:
- Measured VOC Index between 0 and 500.
+ VOC Index
:return nox_index:
- Measured NOx Index between 0 and 500.
+ NOx Index
"""
(mass_concentration_pm1p0_raw, mass_concentration_pm2p5_raw, mass_concentration_pm4p0_raw,
mass_concentration_pm10p0_raw, humidity_raw, temperature_raw, voc_index_raw, nox_index_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), SignalVocIndex(voc_index_raw), SignalNoxIndex(nox_index_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), SignalDividedBy10Int16(voc_index_raw),
+ SignalDividedBy10Int16(nox_index_raw))
def read_number_concentration_values(self):
"""
@@ -610,8 +633,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_sen65/response_provider.py b/sensirion_i2c_sen65/response_provider.py
index c03eaaa..3f9e6d6 100644
--- a/sensirion_i2c_sen65/response_provider.py
+++ b/sensirion_i2c_sen65/response_provider.py
@@ -4,7 +4,8 @@
class Sen65ResponseProvider(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_sen65/result_types.py b/sensirion_i2c_sen65/result_types.py
index bbf1815..dd22fba 100644
--- a/sensirion_i2c_sen65/result_types.py
+++ b/sensirion_i2c_sen65/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: sen65
-# Model-Version: 1.3.0
+# Model-Version: 1.4.0
#
"""
The signal classes specify transformations of the raw sensor signals into a meaningful units.
@@ -17,134 +17,42 @@
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
+ return self._divided_by_10_uint16
def __str__(self):
return '{0:.2f}'.format(self.value)
-class SignalMassConcentrationPm2p5(AbstractSignal):
- """Mass concentration in μg/m³ for particles smaller than 2.5 μm"""
+class SignalDividedBy10Int16(AbstractSignal):
+ """
+ The VOC and NOx indices are scaled by a factor 10 to avoid
+ floating point operations on the communication interface.
+ """
- def __init__(self, mass_concentration_pm2p5_raw):
- self._mass_concentration_pm2p5 = mass_concentration_pm2p5_raw / 10.0
+ def __init__(self, scaled_integer_value):
+ self._divided_by_10_int16 = scaled_integer_value / 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_int16
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,31 +78,3 @@ def value(self):
def __str__(self):
return '{0:.2f}'.format(self.value)
-
-class SignalVocIndex(AbstractSignal):
- """Measured VOC Index ticks."""
-
- def __init__(self, voc_index_raw):
- self._voc_index = voc_index_raw / 10.0
-
- @property
- def value(self):
- return self._voc_index
-
- def __str__(self):
- return '{0:.2f}'.format(self.value)
-
-
-class SignalNoxIndex(AbstractSignal):
- """Measured NOx Index ticks."""
-
- def __init__(self, nox_index_raw):
- self._nox_index = nox_index_raw / 10.0
-
- @property
- def value(self):
- return self._nox_index
-
- def __str__(self):
- return '{0:.2f}'.format(self.value)
-
diff --git a/sensirion_i2c_sen65/version.py b/sensirion_i2c_sen65/version.py
index 338edf5..b42242e 100644
--- a/sensirion_i2c_sen65/version.py
+++ b/sensirion_i2c_sen65/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_sen65")
diff --git a/setup.py b/setup.py
index 561f260..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_sen65/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_sen65',
- version=version_string,
- author='Sensirion',
- author_email='info@sensirion.com',
- description='I2C driver for the Sensirion SEN65 sensor family',
- license='BSD',
- keywords="""Sensirion SEN65
- I2C
- SEN65""",
- project_urls={
- "Documentation": "https://sensirion.github.io/python-i2c-sen65",
- "Repository": "https://github.com/Sensirion/python-i2c-sen65",
- "Changelog": "https://github.com/Sensirion/python-i2c-sen65/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_sen65.py b/tests/test_sen65.py
index 612c406..5bf3e60 100644
--- a/tests/test_sen65.py
+++ b/tests/test_sen65.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: sen65
-# Model-Version: 1.3.0
+# Model-Version: 1.4.0
#
import pytest
@@ -24,6 +24,12 @@ def sensor(channel_provider):
yield Sen65Device(channel)
+def test_get_product_type1(sensor):
+ product_type = sensor.get_product_type()
+ print(f"product_type: {product_type}; "
+ )
+
+
def test_get_product_name1(sensor):
product_name = sensor.get_product_name()
print(f"product_name: {product_name}; "
@@ -48,8 +54,24 @@ def test_set_temperature_offset_parameters1(sensor):
sensor.set_temperature_offset_parameters(1, 10, 1, 0)
-def test_set_voc_algorithm_tuning_parameters1(sensor):
- sensor.set_voc_algorithm_tuning_parameters(100, 12, 12, 180, 50, 230)
+def test_set_temperature_acceleration_parameters1(sensor):
+ sensor.set_temperature_acceleration_parameters(1, 1, 1, 1)
+
+
+def test_activate_sht_heater1(sensor):
+ sensor.activate_sht_heater()
+
+
+def test_read_device_status1(sensor):
+ device_status = sensor.read_device_status()
+ print(f"device_status: {device_status}; "
+ )
+
+
+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_voc_algorithm_tuning_parameters1(sensor):
@@ -65,8 +87,8 @@ def test_get_voc_algorithm_tuning_parameters1(sensor):
)
-def test_set_nox_algorithm_tuning_parameters1(sensor):
- sensor.set_nox_algorithm_tuning_parameters(1, 12, 12, 720, 50, 230)
+def test_set_voc_algorithm_tuning_parameters1(sensor):
+ sensor.set_voc_algorithm_tuning_parameters(100, 12, 12, 180, 50, 230)
def test_get_nox_algorithm_tuning_parameters1(sensor):
@@ -82,8 +104,8 @@ def test_get_nox_algorithm_tuning_parameters1(sensor):
)
-def test_set_temperature_acceleration_parameters1(sensor):
- sensor.set_temperature_acceleration_parameters(1, 1, 1, 1)
+def test_set_nox_algorithm_tuning_parameters1(sensor):
+ sensor.set_nox_algorithm_tuning_parameters(1, 12, 12, 720, 50, 230)
def test_get_voc_algorithm_state1(sensor):
@@ -92,22 +114,6 @@ def test_get_voc_algorithm_state1(sensor):
)
-def test_activate_sht_heater1(sensor):
- sensor.activate_sht_heater()
-
-
-def test_read_device_status1(sensor):
- device_status = sensor.read_device_status()
- print(f"device_status: {device_status}; "
- )
-
-
-def test_read_and_clear_device_status1(sensor):
- device_status = sensor.read_and_clear_device_status()
- print(f"device_status: {device_status}; "
- )
-
-
def test_start_continuous_measurement1(sensor):
sensor.start_continuous_measurement()
(padding, data_ready
@@ -165,8 +171,5 @@ def test_start_continuous_measurement1(sensor):
f"raw_nox: {raw_nox}; "
)
sensor.set_temperature_offset_parameters(1, 10, 1, 0)
- state = sensor.get_voc_algorithm_state()
- print(f"state: {state}; "
- )
sensor.stop_measurement()