Coverage for src / bluetooth_sig / gatt / characteristics / apparent_energy_32.py: 100%

12 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-11 20:14 +0000

1"""Apparent Energy 32 characteristic implementation.""" 

2 

3from __future__ import annotations 

4 

5from ..context import CharacteristicContext 

6from .base import BaseCharacteristic 

7from .utils.data_parser import DataParser 

8 

9 

10class ApparentEnergy32Characteristic(BaseCharacteristic[float]): 

11 """Apparent Energy 32 characteristic (0x2B89). 

12 

13 org.bluetooth.characteristic.apparent_energy_32 

14 

15 The Apparent Energy 32 characteristic is used to represent the integral of Apparent Power over a time interval. 

16 """ 

17 

18 _manual_unit: str | None = ( 

19 "kVAh" # YAML: electrical_apparent_energy.kilovolt_ampere_hour, units.yaml: energy.kilovolt_ampere_hour 

20 ) 

21 

22 def _decode_value(self, data: bytearray, ctx: CharacteristicContext | None = None) -> float | None: 

23 """Decode apparent energy 32 characteristic. 

24 

25 Decodes a 32-bit unsigned integer representing apparent energy in 0.001 kVAh increments 

26 per Bluetooth SIG Apparent Energy 32 characteristic specification. 

27 

28 Args: 

29 data: Raw bytes from BLE characteristic (exactly 4 bytes, little-endian) 

30 ctx: Optional context for parsing (device info, flags, etc.) 

31 

32 Returns: 

33 Apparent energy in kilovolt ampere hours, or None if value is not valid or unknown 

34 

35 Raises: 

36 InsufficientDataError: If data is not exactly 4 bytes 

37 """ 

38 raw_value = DataParser.parse_int32(data, 0, signed=False) 

39 return raw_value * 0.001 

40 

41 def _encode_value(self, data: float) -> bytearray: 

42 """Encode apparent energy value.""" 

43 raw_value = int(data / 0.001) 

44 return DataParser.encode_int32(raw_value, signed=False)