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 2a29a62..d2d0f78 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -8,3 +8,5 @@ on: 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 b1cebfa..c15f72f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,5 +8,9 @@ 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 14a80aa..50ba45f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.1.0] - 2026-4-30 + +### Changed + +- Updated busy-delay from 2ms to 1ms for `enter_sleep_mode` command. +- Add `check_self_test` to examples. ## [1.0.0] - 2025-6-20 ### Added - Initial support for STCC4. -[Unreleased]: https://github.com/Sensirion/python-i2c-stcc4/compare/1.0.0...HEAD +[Unreleased]: https://github.com/Sensirion/python-i2c-stcc4/compare/1.1.0...HEAD +[1.1.0]: https://github.com/Sensirion/python-i2c-stcc4/compare/1.0.0...1.1.0 [1.0.0]: https://github.com/Sensirion/python-i2c-stcc4/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 0754af9..2771e15 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,13 @@ This repository contains the Python driver to communicate with a Sensirion STCC4 Click [here](https://sensirion.com/products/catalog/STCC4) to learn more about the Sensirion STCC4 sensor. +The STCC4 is Sensirion's next generation miniature CO2 sensor for indoor air quality applications. + + The default I²C address of [STCC4](https://sensirion.com/products/catalog/STCC4) is **0x64**. -> [!NOTE] -> The SEK-STCC4 board from Sensirion includes a STCC4 and a SHT4x for temperature and humidity compensation, which is controlled by the STCC4 through the integrated I2C controller interface. The provided examples are designed considering this sensor configuration. + ## Connect the sensor diff --git a/docs/conf.py b/docs/conf.py index bfa646a..f120ec5 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_stcc4 @@ -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_stcc4') +distribution = metadata.distribution("sensirion_i2c_stcc4") -project = u'sensirion_i2c_stcc4' +project = distribution.name copyright = u'{} Sensirion AG, Switzerland'.format(datetime.now().year) author = 'Sensirion AG' # The short X.Y version -version = sensirion_i2c_stcc4.__version__ +version = distribution.version # The full version, including alpha/beta/rc tags -release = sensirion_i2c_stcc4.__version__ +release = distribution.version # -- General configuration --------------------------------------------------- diff --git a/examples/example_usage_linux_stcc4.py b/examples/example_usage_linux_stcc4.py index b7c4a07..beaa629 100644 --- a/examples/example_usage_linux_stcc4.py +++ b/examples/example_usage_linux_stcc4.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.2.0 +# Generator: sensirion-driver-generator 1.6.1 # Product: stcc4 -# Model-Version: 3.4.0 +# Model-Version: 3.5.0 # import argparse @@ -26,24 +26,25 @@ crc=CrcCalculator(8, 0x31, 0xff, 0x0)) sensor = Stcc4Device(channel) sensor.stop_continuous_measurement() - (product_id, serial_number) = sensor.get_product_id() - print(f"product_id: {product_id}; serial_number: {serial_number}; ") + (product_id, serial_number + ) = sensor.get_product_id() + print(f"product_id: {product_id}; " + f"serial_number: {serial_number}; " + ) + test_result = sensor.check_self_test() + print(f"test_result: {test_result}; " + ) sensor.start_continuous_measurement() for i in range(50): - time.sleep(1.0) try: - (co2_concentration, temperature, relative_humidity, sensor_status) = sensor.read_measurement() + time.sleep(1.0) + (co2_concentration, temperature, relative_humidity, sensor_status + ) = sensor.read_measurement() + print(f"co2_concentration: {co2_concentration}; " + f"temperature: {temperature}; " + f"relative_humidity: {relative_humidity}; " + f"sensor_status: {sensor_status}; " + ) except BaseException: - # Read can fail in case of clock shift, datasheet suggests to retry after 150ms - time.sleep(0.15) - try: - (co2_concentration, temperature, relative_humidity, sensor_status) = sensor.read_measurement() - except BaseException: - continue - - print(f"co2_concentration: {co2_concentration}; " - f"temperature: {temperature}; " - f"relative_humidity: {relative_humidity}; " - f"sensor_status: {sensor_status}; ") - + continue sensor.stop_continuous_measurement() diff --git a/examples/example_usage_sensorbridge_stcc4.py b/examples/example_usage_sensorbridge_stcc4.py index f92e6fd..b83c37a 100644 --- a/examples/example_usage_sensorbridge_stcc4.py +++ b/examples/example_usage_sensorbridge_stcc4.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.2.0 +# Generator: sensirion-driver-generator 1.6.1 # Product: stcc4 -# Model-Version: 3.4.0 +# Model-Version: 3.5.0 # import argparse @@ -40,21 +40,20 @@ print(f"product_id: {product_id}; " f"serial_number: {serial_number}; " ) + test_result = sensor.check_self_test() + print(f"test_result: {test_result}; " + ) sensor.start_continuous_measurement() for i in range(50): - time.sleep(1.0) try: - (co2_concentration, temperature, relative_humidity, sensor_status) = sensor.read_measurement() + time.sleep(1.0) + (co2_concentration, temperature, relative_humidity, sensor_status + ) = sensor.read_measurement() + print(f"co2_concentration: {co2_concentration}; " + f"temperature: {temperature}; " + f"relative_humidity: {relative_humidity}; " + f"sensor_status: {sensor_status}; " + ) except BaseException: - # Read can fail in case of clock shift, datasheet suggests to retry after 150ms - time.sleep(0.15) - try: - (co2_concentration, temperature, relative_humidity, sensor_status) = sensor.read_measurement() - except BaseException: - continue - print(f"co2_concentration: {co2_concentration}; " - f"temperature: {temperature}; " - f"relative_humidity: {relative_humidity}; " - f"sensor_status: {sensor_status}; " - ) + continue sensor.stop_continuous_measurement() diff --git a/examples/example_usage_single_shot_linux_stcc4.py b/examples/example_usage_single_shot_linux_stcc4.py index 2865551..380fcdc 100644 --- a/examples/example_usage_single_shot_linux_stcc4.py +++ b/examples/example_usage_single_shot_linux_stcc4.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.2.0 +# Generator: sensirion-driver-generator 1.6.1 # Product: stcc4 -# Model-Version: 3.4.0 +# Model-Version: 3.5.0 # import argparse @@ -31,6 +31,12 @@ sensor.exit_sleep_mode() sensor.stop_continuous_measurement() + # Perform self-test + self_test_result = sensor.check_self_test() + if not self_test_result: + print("Self-test failed!" + ) + # Enter sleep mode sensor.enter_sleep_mode() for i in range(100): diff --git a/examples/example_usage_single_shot_sensorbridge_stcc4.py b/examples/example_usage_single_shot_sensorbridge_stcc4.py index 6e6f39b..9da879b 100644 --- a/examples/example_usage_single_shot_sensorbridge_stcc4.py +++ b/examples/example_usage_single_shot_sensorbridge_stcc4.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.2.0 +# Generator: sensirion-driver-generator 1.6.1 # Product: stcc4 -# Model-Version: 3.4.0 +# Model-Version: 3.5.0 # import argparse @@ -40,6 +40,12 @@ sensor.exit_sleep_mode() sensor.stop_continuous_measurement() + # Perform self-test + self_test_result = sensor.check_self_test() + if not self_test_result: + print("Self-test failed!" + ) + # Enter sleep mode sensor.enter_sleep_mode() for i in range(100): diff --git a/metadata.yml b/metadata.yml index 9d21483..a136a54 100644 --- a/metadata.yml +++ b/metadata.yml @@ -1,7 +1,7 @@ # driver generation metadata -generator_version: 1.2.0 -model_version: 3.4.0 +generator_version: 1.6.1 +model_version: 3.5.0 dg_status: released -is_manually_modified: true +is_manually_modified: false first_generated: '2025-02-24 11:47' -last_generated: '2025-06-20 08:02' +last_generated: '2026-04-30 11:42' diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..991c888 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,66 @@ +[build-system] +requires = ["hatchling >= 1.26", "wheel >= 0.45.0"] +build-backend = "hatchling.build" + +[project] +name = "sensirion_i2c_stcc4" +description = "I2C driver for the Sensirion STCC4 sensor family" + +readme = "README.md" +version = "1.1.0" +requires-python = ">=3.8,<4.0" + +authors = [ + { name = "Sensirion", email = "info@sensirion.com" }, +] + +license = "BSD-3-Clause" +license-files = ["LICENSE"] + +keywords = [ + "Sensirion STCC4", + "I2C", + "STCC4", + ] + +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==8.2.3", + "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-stcc4/blob/master/CHANGELOG.md" +Repository = "https://github.com/Sensirion/python-i2c-stcc4" +Documentation = "https://sensirion.github.io/python-i2c-stcc4" + diff --git a/sensirion_i2c_stcc4/commands.py b/sensirion_i2c_stcc4/commands.py index 7b042bb..3b33e9c 100644 --- a/sensirion_i2c_stcc4/commands.py +++ b/sensirion_i2c_stcc4/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.2.0 +# Generator: sensirion-driver-generator 1.6.1 # Product: stcc4 -# Model-Version: 3.4.0 +# Model-Version: 3.5.0 # """ The transfer classes specify the data that is transferred between host and sensor. The generated transfer classes diff --git a/sensirion_i2c_stcc4/device.py b/sensirion_i2c_stcc4/device.py index bc97b93..5433098 100644 --- a/sensirion_i2c_stcc4/device.py +++ b/sensirion_i2c_stcc4/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.2.0 +# Generator: sensirion-driver-generator 1.6.1 # Product: stcc4 -# Model-Version: 3.4.0 +# Model-Version: 3.5.0 # """ The class Stcc4DeviceBase implements the low level interface of the sensor. @@ -249,7 +249,7 @@ def __init__(self, channel): def read_measurement(self): """ - reads measurement data + Reads measurement data from the sensor and returns the CO2 concentration in ppm, the temperature in °C, the relative humidity in %RH and the sensor status. :return co2_concentration: @@ -275,3 +275,19 @@ def set_pressure_compensation(self, pressure): """ self.stcc4.set_pressure_compensation_raw(int(pressure / 2)) + + def check_self_test(self): + """ + Check if the self-test is successful. + + :return test_result: + + """ + self_test_result = 0 + try: + self_test_result = self.stcc4.perform_self_test() + + except: # noqa + return False + + return self_test_result == 0 diff --git a/sensirion_i2c_stcc4/result_types.py b/sensirion_i2c_stcc4/result_types.py index 613bbc7..9f06909 100644 --- a/sensirion_i2c_stcc4/result_types.py +++ b/sensirion_i2c_stcc4/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.2.0 +# Generator: sensirion-driver-generator 1.6.1 # Product: stcc4 -# Model-Version: 3.4.0 +# Model-Version: 3.5.0 # """ The signal classes specify transformations of the raw sensor signals into a meaningful units. @@ -18,7 +18,7 @@ class SignalTemperature(AbstractSignal): - """""" + """Convert raw temperature values to physical values in °C""" def __init__(self, raw_temperature): self._temperature = -45.0 + ((175.0 * raw_temperature) / 65535.0) @@ -32,7 +32,7 @@ def __str__(self): class SignalRelativeHumidity(AbstractSignal): - """""" + """Convert raw relative humidity values to physical values in %RH""" def __init__(self, raw_relative_humidity): self._relative_humidity = -6.0 + ((125.0 * raw_relative_humidity) / 65535.0) diff --git a/sensirion_i2c_stcc4/version.py b/sensirion_i2c_stcc4/version.py index e5ed854..7339b99 100644 --- a/sensirion_i2c_stcc4/version.py +++ b/sensirion_i2c_stcc4/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 = "1.0.0" +version: Final[str] = metadata.version("sensirion_i2c_stcc4") diff --git a/setup.py b/setup.py index 935b5b3..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.3.0,<3.0', - 'sensirion-driver-support-types>=1.2.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_stcc4/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_stcc4', - version=version_string, - author='Sensirion', - author_email='info@sensirion.com', - description='I2C driver for the Sensirion STCC4 sensor family', - license='BSD', - keywords="""Sensirion STCC4 - I2C - STCC4""", - project_urls={ - "Documentation": "https://sensirion.github.io/python-i2c-stcc4", - "Repository": "https://github.com/Sensirion/python-i2c-stcc4", - "Changelog": "https://github.com/Sensirion/python-i2c-stcc4/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_stcc4.py b/tests/test_stcc4.py index f9d4bd5..5fcefc3 100644 --- a/tests/test_stcc4.py +++ b/tests/test_stcc4.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.2.0 +# Generator: sensirion-driver-generator 1.6.1 # Product: stcc4 -# Model-Version: 3.4.0 +# Model-Version: 3.5.0 # import pytest @@ -32,6 +32,12 @@ def test_get_product_id1(sensor): ) +def test_check_self_test1(sensor): + test_result = sensor.check_self_test() + print(f"test_result: {test_result}; " + ) + + def test_set_rht_compensation1(sensor): sensor.set_rht_compensation(26214, 29359)