Skip to content
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add interface for totalizer
- Ensure linux file endings across the package
- Fix several typos
- Update GitHub actions to latest versions
- Update GitHub actions to the latest versions
- Update dependencies
- Improve usage examples

## [1.1.1] - 2024-4-10

Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ We provide two examples to show two basic usage scenarios of the driver
python ./examples/scc1_slf3x_example/slf3x_usage.py --serial-port <your-com-port>
```

- **SLF3x Totalizer Usage**
This example enables the totalizer, resets it before starting a measurement, and prints the accumulated totalizer flow together with the sensor's configured unit.

```bash
python ./examples/scc1_slf3x_example/slf3x_totalizer_usage.py --serial-port <your-com-port>
```

- **USB-I2c-Bridge**
This example shows how a public python driver can be used with the SCC1-USB cable. The example uses the public driver `sensirion_i2c_sf06_lf`. Before you run the example you need to install this driver.

Expand Down
45 changes: 45 additions & 0 deletions examples/scc1_slf3x_example/slf3x_totalizer_usage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import argparse
import time

from sensirion_shdlc_driver import ShdlcSerialPort, ShdlcConnection

from sensirion_uart_scc1.drivers.scc1_slf3x import Scc1Slf3x
from sensirion_uart_scc1.drivers.slf_common import get_volume_unit_label, SlfProductName
from sensirion_uart_scc1.scc1_shdlc_device import Scc1ShdlcDevice

parser = argparse.ArgumentParser()
parser.add_argument('--serial-port', '-p', default='COM5')
args = parser.parse_args()

with ShdlcSerialPort(port=args.serial_port, baudrate=115200) as port:
device = Scc1ShdlcDevice(ShdlcConnection(port), target_address=0)
device.sensor_reset()
device.set_sensor_type(Scc1Slf3x.SENSOR_TYPE)
sensor = Scc1Slf3x(device)

print(f'Product: {SlfProductName.from_product_id(sensor.product_id)}')
print(f"product id: 0x{sensor.product_id:08X}")
print(f"Serial number: {sensor.serial_number}")

flow_scale, unit = sensor.get_flow_unit_and_scale()
if flow_scale is None or unit is None:
raise RuntimeError("Could not determine the sensor flow unit and scale")
volume_unit_label = get_volume_unit_label(unit)

sensor.set_totalizator_status(True)
sensor.reset_totalizator()
# Measure as fast as possible
sensor.start_continuous_measurement(interval_ms=0)
try:
for _ in range(10):
time.sleep(1)
totalizer_value = sensor.get_totalizator_value()
if totalizer_value is None:
print("Totalizer value not available")
continue

totalized_flow = totalizer_value / flow_scale
print(f"Totalizer volume: {totalized_flow} {volume_unit_label}")

finally:
sensor.stop_continuous_measurement()
24 changes: 16 additions & 8 deletions examples/scc1_slf3x_example/slf3x_usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from sensirion_shdlc_driver import ShdlcSerialPort, ShdlcConnection

from sensirion_uart_scc1.drivers.scc1_slf3x import Scc1Slf3x
from sensirion_uart_scc1.drivers.slf_common import get_flow_unit_label
from sensirion_uart_scc1.drivers.slf_common import get_flow_unit_label, SlfProductName
from sensirion_uart_scc1.scc1_shdlc_device import Scc1ShdlcDevice

parser = argparse.ArgumentParser()
Expand All @@ -12,19 +12,27 @@

with ShdlcSerialPort(port=args.serial_port, baudrate=115200) as port:
device = Scc1ShdlcDevice(ShdlcConnection(port), target_address=0)
device.sensor_reset()
device.set_sensor_type(Scc1Slf3x.SENSOR_TYPE)
sensor = Scc1Slf3x(device)
print("serial_number:", sensor.serial_number)
print("product id:", sensor.product_id)
print("Flow;\tTemperature;\t Flag")

print(f'Product: {SlfProductName.from_product_id(sensor.product_id)}')
print(f"product id: 0x{sensor.product_id:08X}")
print(f"Serial number: {sensor.serial_number}")

print("Flow;\tTemperature;\tAir In Line;\tHigh Flow")
flow_scale, unit = sensor.get_flow_unit_and_scale()
unit_label = get_flow_unit_label(unit)
sensor.start_continuous_measurement(interval_ms=2)
try:
for _ in range(1000):
for _ in range(50):
remaining, lost, data = sensor.read_extended_buffer()
print(f"Remaining bytes {remaining} and {lost}-sample lost")
print()
for flow, temperature, flag in data:
print(f'{flow / flow_scale} {get_flow_unit_label(unit)};\t{temperature / 200} C;\t {flag}')
air_in_line = bool(flag & 0x01)
high_flow = bool((flag >> 1) & 0x01)
flow_scaled = flow / flow_scale
temperature_scaled = temperature / 200

print(f'{flow_scaled:.3f} {unit_label};\t{temperature_scaled:.3f} C;\t{air_in_line};\t{high_flow}')
finally:
sensor.stop_continuous_measurement()
14 changes: 10 additions & 4 deletions examples/scc1_usb_to_i2c/scc1_usb_2_i2c_usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
from sensirion_i2c_sf06_lf.device import Sf06LfDevice
from sensirion_shdlc_driver import ShdlcSerialPort, ShdlcConnection

from sensirion_uart_scc1.drivers.slf_common import SlfProductName
from sensirion_uart_scc1.scc1_shdlc_device import Scc1ShdlcDevice

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

channel = I2cChannel(bridge.get_i2c_transceiver(),
Expand All @@ -25,11 +27,15 @@
time.sleep(0.1)
except BaseException:
...
(product_identifier, serial_number
) = sensor.read_product_identifier()
print(f"product_identifier: {product_identifier}; " f"serial_number: {serial_number}; ")

product_identifier, serial_number = sensor.read_product_identifier()

print(f'Product: {SlfProductName.from_product_id(sensor.product_id)}')
print(f"product id: 0x{sensor.product_id:08X}")
print(f"Serial number: {sensor.serial_number}")

sensor.start_h2o_continuous_measurement()
for i in range(500):
for i in range(50):
try:
time.sleep(0.02)
(a_flow, a_temperature, a_signaling_flags
Expand Down
18 changes: 15 additions & 3 deletions sensirion_uart_scc1/drivers/slf_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from collections import OrderedDict
from enum import Enum
from typing import Optional

from sensirion_uart_scc1.scc1_exceptions import Scc1InvalidProductId

Expand All @@ -23,7 +24,7 @@ class SlfMode(Enum):
LIQUI_8 = 'Liquid 8'


class SlfMeasurementCommand(object):
class SlfMeasurementCommand:
MEASUREMENT_COMMANDS = {
SlfMode.LIQUI_0: 0x3603,
SlfMode.LIQUI_1: 0x3608,
Expand Down Expand Up @@ -79,7 +80,9 @@ class SlfProduct(Enum):
SF06 = 'SF06'

@staticmethod
def from_product_id(product_id: int) -> SlfProduct:
def from_product_id(product_id: Optional[int]) -> SlfProduct:
# remove last byte of the product id for detection
product_id = product_id >> 8
if product_id in SLF3x_PRODUCT_IDS:
return SlfProduct.SLF3x
elif product_id in LD20_2600B_PRODUCT_IDS:
Expand All @@ -91,7 +94,10 @@ def from_product_id(product_id: int) -> SlfProduct:

class SlfProductName:
@staticmethod
def from_product(product: SlfProduct, product_id: int) -> str:
def from_product_id(product_id: Optional[int]) -> str:
# remove last byte of the product id for detection
product = SlfProduct.from_product_id(product_id)
product_id = product_id >> 8
if product is SlfProduct.SLF3x:
return SLF3x_PRODUCT_NAME.get(product_id, 'SLF3x')
elif product is SlfProduct.LD20:
Expand Down Expand Up @@ -169,3 +175,9 @@ def get_flow_unit_label(flow_unit_raw: int) -> str:
time_base = FLOW_UNIT_TIME_BASE.get((flow_unit_raw >> 4) & 0xF, '')
volume = FLOW_UNIT_VOLUME.get((flow_unit_raw >> 8) & 0xF, '')
return f'{prefix}{volume}/{time_base}'


def get_volume_unit_label(flow_unit_raw: int) -> str:
prefix = FLOW_UNIT_PREFIX.get(flow_unit_raw & 0xF, '')
volume = FLOW_UNIT_VOLUME.get((flow_unit_raw >> 8) & 0xF, '')
return f'{prefix}{volume}'
Loading