Coverage for src/bluetooth_sig/gatt/characteristics/voc_concentration.py: 100%
26 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-30 00:10 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-30 00:10 +0000
1"""VOC Concentration characteristic implementation."""
3from __future__ import annotations
5from typing import cast
7from ..context import CharacteristicContext
8from .base import BaseCharacteristic
9from .templates import Uint16Template
12# Special value constants for VOC Concentration characteristic
13class VOCConcentrationValues: # pylint: disable=too-few-public-methods
14 """Special values for VOC Concentration characteristic per Bluetooth SIG specification."""
16 VALUE_65534_OR_GREATER = 0xFFFE # Indicates value is 65534 or greater
17 VALUE_UNKNOWN = 0xFFFF # Indicates value is not known
20class VOCConcentrationCharacteristic(BaseCharacteristic):
21 """Volatile Organic Compounds concentration characteristic (0x2BE7).
23 Uses uint16 format as per SIG specification.
24 Unit: ppb (parts per billion)
25 Range: 0-65533
26 (VOCConcentrationValues.VALUE_65534_OR_GREATER = ≥65534,
27 VOCConcentrationValues.VALUE_UNKNOWN = unknown)
28 """
30 _template = Uint16Template()
32 _manual_unit: str | None = "ppb" # Unit as per SIG specification
33 min_value: int | float | None = 0
34 max_value: int | float | None = VOCConcentrationValues.VALUE_65534_OR_GREATER - 1 # 65533
36 def decode_value(self, data: bytearray, ctx: CharacteristicContext | None = None) -> int:
37 """Parse VOC concentration value with special value handling."""
38 raw_value = cast(int, super().decode_value(data))
40 # Handle special values per SIG specification
41 if raw_value == VOCConcentrationValues.VALUE_65534_OR_GREATER:
42 # Value is 65534 or greater - return a large value
43 return 65534
44 if raw_value == VOCConcentrationValues.VALUE_UNKNOWN:
45 # Value is not known - could raise exception or return None
46 # For now, return a sentinel value that tests can check
47 raise ValueError("VOC concentration value is not known")
49 return raw_value
51 def encode_value(self, data: int) -> bytearray:
52 """Encode VOC concentration with special value handling."""
53 if data < 0:
54 raise ValueError("VOC concentration cannot be negative")
55 if data >= VOCConcentrationValues.VALUE_65534_OR_GREATER:
56 # Encode as "65534 or greater" per SIG specification
57 return super().encode_value(VOCConcentrationValues.VALUE_65534_OR_GREATER)
59 return super().encode_value(data)