Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sensor type interface #7

Merged
merged 3 commits into from
Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Build and Publish Package to pypi.org
on:
create:
push:
tags:
- "[0-9]+.[0-9]+.[0-9]+"

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
name: Define a cache for the virtual environment based on the dependencies lock file
with:
path: ./.venv
key: venv-${{ hashFiles('poetry.lock') }}
key: venv-${{ matrix.os }}-${{ matrix.python-version }}-${{ hashFiles('poetry.lock') }}
- name: Install the project dependencies
run: poetry install --with test
- name: Verify style with flake8
Expand Down
13 changes: 11 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.1.0] - 2024-4-10

### Added

- Interface to get and set sensor type
- Interface to scan for i2c addresses
- Interface to get/set i2c address

## [1.0.0] - 2024-2-14

### Added

- Provide initial version of this repository containing a driver for the Sensirion SCC1-USB cable.

[Unreleased]: https://github.com/Sensirion/python-uart-scc1/compare/1.0.0...HEAD
[1.0.0]: https://github.com/Sensirion/python-uart-scc1/releases/tag/1.0.0
[Unreleased]: https://github.com/Sensirion/python-uart-scc1/compare/1.1.0...HEAD
[1.1.0]: https://github.com/Sensirion/python-uart-scc1/compare/1.0.0...1.1.0
[1.0.0]: https://github.com/Sensirion/python-uart-scc1/releases/tag/1.0.0
1 change: 1 addition & 0 deletions examples/scc1_slf3x_example/slf3x_usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

with ShdlcSerialPort(port=args.serial_port, baudrate=115200) as port:
device = Scc1ShdlcDevice(ShdlcConnection(port), slave_address=0)
device.set_sensor_type(Scc1Slf3x.SENSOR_TYPE)
sensor = Scc1Slf3x(device)
print("serial_number:", sensor.serial_number)
print("product id:", sensor.product_id)
Expand Down
2 changes: 2 additions & 0 deletions examples/scc1_usb_to_i2c/scc1_usb_2_i2c_usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@

with ShdlcSerialPort(port='COM5', baudrate=115200) as port:
bridge = Scc1ShdlcDevice(ShdlcConnection(port), slave_address=0)
bridge.set_sensor_type(3) # SF06 devices

channel = I2cChannel(bridge.get_i2c_transceiver(),
slave_address=0x08,
crc=CrcCalculator(8, 0x31, 0xff, 0x0))

sensor = Sf06LfDevice(channel)

try:
sensor.stop_continuous_measurement()
time.sleep(0.1)
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "sensirion-uart-scc1"
version = "1.0.0"
version = "1.1.0"
description = "Driver for Sensirion SCC1 USB cable"
authors = ["Pascal Sachs"]
license = "BSD-3-Clause"
Expand Down Expand Up @@ -28,6 +28,7 @@ testpaths = [
"tests"
]


[tool.poetry.group.docs]
optional = true

Expand Down
87 changes: 78 additions & 9 deletions sensirion_uart_scc1/scc1_shdlc_device.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# -*- coding: utf-8 -*-

import logging
from typing import Optional, Iterable, Union
from struct import unpack
from typing import Optional, Iterable, Union, List

from packaging.version import Version
from sensirion_shdlc_driver import ShdlcDevice, ShdlcConnection
Expand All @@ -15,7 +16,7 @@

class Scc1ShdlcDevice(ShdlcDevice):
"""
The Scc1 Shdlc device is used to communicate with various sensor using the Sensirion SCC1 sensor cable.
The Scc1 SHDLC device is used to communicate with various sensors using the Sensirion SCC1 sensor cable.
"""

def __init__(self, connection: ShdlcConnection, slave_address: int = 0) -> None:
Expand All @@ -27,12 +28,15 @@ def __init__(self, connection: ShdlcConnection, slave_address: int = 0) -> None:
super().__init__(connection, slave_address)
self._version = self.get_version()
self._serial_number = self.get_serial_number()
self._sensor_type = self.get_sensor_type()
self._i2c_address = self.get_sensor_address()
self._connected_i2c_addresses: List[int] = []

def __str__(self):
def __str__(self) -> str:
return f"SCC1-{self.serial_number}@{self.com_port}"

@property
def com_port(self):
def com_port(self) -> str:
return self.connection.port.description.split('@')[0]

@property
Expand All @@ -43,10 +47,75 @@ def serial_number(self) -> str:
def firmware_version(self) -> Version:
return Version(str(self._version.firmware))

@property
def connected_i2c_addresses(self) -> List[int]:
"""Returns the connected I2C addresses. You need to call find_chips to fill this attribute."""
return self._connected_i2c_addresses

def perform_i2c_scan(self) -> List[int]:
"""
Looks for i2c devices within a certain range on a certain port
:return: List of i2c addresses that responded to the scan
"""
result = self.transceive(0x29, [0x01], timeout=0.025)
return list(unpack('>{cnt}B'.format(cnt=len(result)), result))

def find_chips(self) -> List[int]:
"""
Looking for chips on all ports and sets the _connected_i2c_addresses attribute
:return: List of connected addresses
"""
self._connected_i2c_addresses = self.perform_i2c_scan()
return self._connected_i2c_addresses

def get_sensor_type(self) -> Optional[int]:
"""
:return: the configured sensor type
"""
result = self.transceive(0x24, [], timeout=0.025)
if result:
return int(unpack('>B', result)[0])
return None

def set_sensor_type(self, sensor_type: int):
"""
Set sensor type
0: Flow Sensor (SF04 based products)
1: Humidity Sensor (SHTxx products)
2: Flow Sensor (SF05 based products)
3: Flow Sensor (SF06 based products) (Firmware ≥1.7)
4: Reserved
:param sensor_type: One of the supported sensor types 0-4

"""
if sensor_type not in range(5):
raise ValueError('Sensor type not supported')
self.transceive(0x24, [sensor_type], timeout=0.01)
self._sensor_type = sensor_type

def get_sensor_address(self) -> Optional[int]:
"""
:return: the configured i2c address
"""
result = self.transceive(0x25, [], timeout=0.025)
if result:
return int(unpack('>B', result)[0])
return None

def set_sensor_address(self, i2c_address: int) -> None:
"""
Configure the sensors i2c address and write it to EEPROM
:param i2c_address: the i2c address
"""
if i2c_address not in range(128):
raise ValueError('I2C address out of range. Address has to be within the range 0...127')
self.transceive(0x25, [i2c_address], timeout=0.01)
self._i2c_address = i2c_address

def sensor_reset(self) -> None:
"""
Execute a hard reset on the sensor and check for correct response. Active
continuous/single measurement is stopped and the sensor is left in idle state.
Execute a hard reset on the sensor and check for the correct response.
Active continuous/single measurement is stopped, and the sensor is left in idle state.
"""
self.transceive(0x66, [], 0.3)

Expand Down Expand Up @@ -74,8 +143,8 @@ def get_i2c_transceiver(self) -> I2cTransceiver:
"""
An I2cTransceiver object is required in or der to use the cable with public python i2c drivers.

In general all functionality of the sensors are available in the public python drivers as well. The
throughput of the public python driver will be lower than the throughput that can be achieved with
the sensor specific api of the SCC1 sensor cable.
In general, all functionality of the sensors is available in the public python drivers as well.
The throughput of the public python driver will be lower than the throughput that can be achieved with
the sensor-specific api of the SCC1 sensor cable.
"""
return Scc1I2cTransceiver(self)