diff --git a/docs/AGENT_GUIDE.md b/docs/AGENT_GUIDE.md
deleted file mode 100644
index aca07c20..00000000
--- a/docs/AGENT_GUIDE.md
+++ /dev/null
@@ -1,281 +0,0 @@
-
-# AGENT GUIDE: Bluetooth SIG Standards Library
-
-This guide is for both human contributors and AI agents working on the Bluetooth SIG standards translation library. It covers implementation patterns, templates, rationale, and agent-specific behaviour. Follow best practices for Python library documentation and PyPI standards.
-
----
-
-## Agent Behaviour and Workflow
-
-This section is for AI agents and automation:
-
-- Always consult official documentation before coding or refactoring.
-- Validate input, output, and error handling against SIG specs.
-- Proactively check for duplication, unclear instructions, and broken references.
-- Communicate in concise, technical, iterative updates (see memory file).
-- If documentation is missing, escalate and flag for human review.
-- Run format, lint, and tests before claiming any solution works.
-- Never hardcode UUIDs; use registry-driven resolution.
-- Raise clear, specific errors and add/maintain tests for all new features.
-
-References for agents:
-
-- See `.github/instructions/memory.instruction.md` for agent memory and preferences.
-- See `.github/copilot-instructions.md` for agent checklist.
-- [Bluetooth SIG assigned numbers](https://www.bluetooth.com/specifications/assigned-numbers/)
-- [Python documentation](https://docs.python.org/)
-
----
-
-## Table of Contents (Human Coding Guide)
-
-1. [Development Workflow](#development-workflow)
-2. [Implementation Patterns](#implementation-patterns)
-3. [Registry Registration](#registry-registration)
-4. [Testing & Quality](#testing--quality)
-5. [Common Data Parsing Standards](#common-data-parsing-standards)
-6. [Critical Success Factors](#critical-success-factors)
-7. [Framework-Agnostic Integration](#framework-agnostic-integration)
-8. [Template System](#template-system)
-9. [Validation Attributes](#validation-attributes)
-10. [Error Handling](#error-handling)
-11. [Import Organization](#import-organization)
-
----
-
----
-
-## Development Workflow
-
-### Virtual Environment Setup
-
-```bash
-python -m venv .venv
-source .venv/bin/activate # Linux/Mac - Windows: .venv\Scripts\activate
-pip install -e ".[dev]"
-```
-
-### Essential Commands
-
-```bash
-# Initialize Bluetooth SIG submodule (BLOCKING REQUIREMENT):
-git submodule init && git submodule update
-
-# Verify framework functionality:
-python -c "import bluetooth_sig; print('â
Framework ready')"
-
-# Test registry loading:
-python -m pytest tests/test_uuid_registry.py -v
-```
-
----
-
----
-
-## Implementation Patterns
-
-### Standard Characteristic Pattern
-
-ALL characteristics MUST follow this exact pattern:
-
-```python
-from __future__ import annotations
-from dataclasses import dataclass
-from .base import BaseCharacteristic
-
-@dataclass
-class TemperatureCharacteristic(BaseCharacteristic):
- """Temperature measurement per SIG spec."""
-
- def __post_init__(self):
- self.value_type = "float" # string|int|float|boolean|bytes
- super().__post_init__()
-
- def decode_value(self, data: bytearray) -> float:
- """Parse raw bytes with proper validation."""
- if len(data) < 2:
- raise ValueError("Temperature data must be at least 2 bytes")
- raw_value = int.from_bytes(data[:2], byteorder="little", signed=True)
- return raw_value * 0.01 # Apply SIG scaling factor
-
- @property
- def unit(self) -> str:
- return "°C"
-```
-
----
-
----
-
-## Registry Registration
-
-Register in `characteristics/__init__.py`:
-
-```python
-from .temperature import TemperatureCharacteristic
-
-class CharacteristicRegistry:
- _characteristics: dict[str, type[BaseCharacteristic]] = {
- "Temperature": TemperatureCharacteristic, # Must match SIG name
- # ... existing characteristics
- }
-```
-
----
-
----
-
-## Testing & Quality
-
-### Core Validation (Run these commands in sequence)
-
-```bash
-./scripts/format.sh --fix # Fix formatting
-./scripts/format.sh --check # Verify formatting
-./scripts/lint.sh --all # Full linting
-python -m pytest tests/ -v # All tests
-```
-
-**For stubborn issues:**
-
-```bash
-./scripts/format.sh --fix-unsafe # Use ruff unsafe fixes if needed
-```
-
----
-
----
-
-## Common Data Parsing Standards
-
-Based on SIG specifications:
-
-- **Temperature**: sint16, 0.01°C resolution, little endian
-- **Humidity**: uint16, 0.01% resolution, little endian
-- **Pressure**: uint32, 0.1 Pa resolution â convert to hPa
-- **Battery**: uint8, direct percentage value
-
----
-
----
-
-## Critical Success Factors
-
-1. **Submodule Dependency**: `bluetooth_sig/` must be initialized
-2. **Quality Standards**: Run format --fix, --check, lint --all, pytest -v in sequence
-3. **Registry Validation**: All tests must pass
-4. **Type Safety**: Use modern `Class | None` union syntax
-5. **SIG Compliance**: Follow official Bluetooth specifications exactly
-
----
-
----
-
-## Framework-Agnostic Integration
-
-**CRITICAL**: This library works with ANY BLE connection library. The integration pattern is:
-
-```python
-# Step 1: Get raw data (using ANY BLE library)
-raw_data = await your_ble_library.read_characteristic(device, uuid)
-
-# Step 2: Parse with bluetooth_sig (connection-agnostic)
-from bluetooth_sig import BluetoothSIGTranslator
-translator = BluetoothSIGTranslator()
-result = translator.parse_characteristic(uuid, raw_data)
-
-# Step 3: Use parsed result
-print(f"Value: {result.value} {result.unit}")
-```
-
-**Supported BLE Libraries**: bleak-retry-connector, simplepyble, or any custom BLE implementation.
-
----
-
----
-
-## Template System
-
-Use templates in `characteristics/templates.py` for common characteristic types:
-
-```python
-# For simple uint8 characteristics (battery level, etc.)
-@dataclass
-class SimpleUint8Characteristic(BaseCharacteristic):
- expected_length: int = 1
- min_value: int = 0
- max_value: int = 255
- expected_type: type = int
-```
-
----
-
----
-
-## Validation Attributes
-
-Use declarative validation in characteristic classes:
-
-```python
-@dataclass
-class BatteryLevelCharacteristic(BaseCharacteristic):
- """Battery level with validation constraints."""
-
- # Declarative validation (automatically enforced)
- expected_length: int = 1
- min_value: int = 0
- max_value: int = 100
- expected_type: type = int
-
- def decode_value(self, data: bytearray) -> int:
- return data[0] # Validation happens automatically
-```
-
----
-
----
-
-## Error Handling
-
-**Use specific ValueError messages** that reference the characteristic:
-
-```python
-def decode_value(self, data: bytearray) -> float:
- if len(data) < 2:
- raise ValueError("Temperature data must be at least 2 bytes")
- # ... parsing logic
-```
-
-**Handle SIG special values** appropriately:
-
-- `0x07FF`: Positive infinity
-- `0x0800`: Negative infinity
-- `0x07FE`: NaN (Not a Number)
-
----
-
----
-
-## Import Organization
-
-**Always follow this import order:**
-
-1. `from __future__ import annotations` (first line after docstring)
-2. Standard library imports
-3. Third-party imports
-4. Local imports (relative imports)
-
-**Example:**
-
-```python
-"""Module docstring."""
-
-from __future__ import annotations
-
-import struct
-from dataclasses import dataclass
-from typing import Any
-
-from .base import BaseCharacteristic
-from .utils import IEEE11073Parser
-```
diff --git a/docs/BLUETOOTH_SIG_ARCHITECTURE.md b/docs/BLUETOOTH_SIG_ARCHITECTURE.md
deleted file mode 100644
index c6c25291..00000000
--- a/docs/BLUETOOTH_SIG_ARCHITECTURE.md
+++ /dev/null
@@ -1,560 +0,0 @@
-# Bluetooth SIG Standards Library Architecture
-
-## Repository Structure (Cookiecutter Style)
-
-```text
-bluetooth-sig/
-âââ .github/
-â âââ workflows/
-â â âââ ci.yml # Continuous Integration
-â â âââ coverage.yml # Code coverage reporting
-â â âââ publish.yml # PyPI publishing
-â âââ ISSUE_TEMPLATE/
-â â âââ bug_report.md
-â â âââ feature_request.md
-â âââ dependabot.yml # Dependency updates
-âââ .gitignore
-âââ .pre-commit-config.yaml # Pre-commit hooks
-âââ pyproject.toml # Project configuration
-âââ README.md
-âââ CHANGELOG.md
-âââ LICENSE
-âââ src/
-â âââ bluetooth_sig/ # Core SIG Standards Library
-â âââ __init__.py
-â âââ gatt/ # GATT Layer (Phase 1)
-â â âââ __init__.py
-â â âââ characteristics/ # SIG Characteristic Parsers
-â â â âââ __init__.py
-â â â âââ base.py # BaseCharacteristic abstract class
-â â â âââ battery.py # Battery Level, Battery Power State
-â â â âââ environmental.py # Temperature, Humidity, Pressure
-â â â âââ device_info.py # Manufacturer Name, Model Number
-â â â âââ sensors.py # Generic sensor characteristics
-â â âââ services/ # SIG Service Definitions
-â â â âââ __init__.py
-â â â âââ base.py # BaseService abstract class
-â â â âââ battery_service.py # Battery Service (180F)
-â â â âââ environmental_sensing.py # Environmental Sensing (181A)
-â â â âââ device_information.py # Device Information (180A)
-â â âââ parsers/ # GATT Data Type Parsers
-â â âââ __init__.py
-â â âââ data_types.py # SIG standard data type parsing
-â â âââ units.py # Unit conversions and constants
-â âââ gap/ # GAP Layer (Phase 2 - Future)
-â â âââ __init__.py
-â â âââ advertisements/ # Advertisement interpreters
-â â â âââ __init__.py
-â â â âââ service_resolver.py # Service UUID interpretation
-â â âââ validators/ # SIG compliance validation
-â â âââ __init__.py
-â â âââ standard_compliance.py
-â âââ registry/ # Registry System (Core)
-â â âââ __init__.py
-â â âââ loader.py # YAML database loader
-â â âââ resolver.py # Name-to-UUID resolution
-â â âââ cache.py # Runtime caching system
-â â âââ compiled.py # Compiled/pre-processed registry (Phase 3)
-â âââ database/ # SIG Database (Git Submodule)
-â â âââ characteristics/ # YAML characteristic definitions
-â â âââ services/ # YAML service definitions
-â â âââ data_types/ # YAML data type definitions
-â âââ codegen/ # Code Generation (Phase 3)
-â â âââ __init__.py
-â â âââ compiler.py # YAML-to-Python compiler
-â â âââ templates/ # Code generation templates
-â â â âââ characteristic.py.j2 # Characteristic class template
-â â â âââ service.py.j2 # Service class template
-â â â âââ registry.py.j2 # Registry mapping template
-â â âââ validators.py # Generated code validation
-â âââ utils/ # Utilities
-â âââ __init__.py
-â âââ uuid_helpers.py # UUID manipulation
-â âââ exceptions.py # Custom exceptions
-âââ tests/
-â âââ __init__.py
-â âââ conftest.py # Pytest configuration
-â âââ test_gatt/ # GATT layer tests
-â â âââ test_characteristics.py
-â â âââ test_services.py
-â â âââ test_parsers.py
-â âââ test_registry/ # Registry tests
-â â âââ test_uuid_registry.py
-â â âââ test_name_resolver.py
-â âââ test_integration/ # Integration tests
-â â âââ test_bleak_integration.py
-â â âââ test_real_devices.py
-â âââ benchmarks/ # Performance benchmarks
-â âââ test_parsing_performance.py
-âââ examples/ # Usage examples
-â âââ basic_usage.py # Simple characteristic parsing
-â âââ bleak_integration.py # With bleak-retry-connector
-â âââ service_discovery.py # Service and characteristic discovery
-â âââ custom_parsers.py # Extending with custom parsers
-âââ docs/ # Documentation
-â âââ index.md
-â âââ api.md
-â âââ examples.md
-â âââ contributing.md
-âââ bluetooth_sig_data/ # Bluetooth SIG specification data
-â âââ services/ # Service specifications
-â âââ characteristics/ # Characteristic specifications
-â âââ data_types/ # Standard data type definitions
-âââ scripts/ # Development scripts
- âââ generate_docs.py
- âââ update_sig_data.py
-
-## Core Architecture Layers
-
-### 1. GATT Layer (`src/bluetooth_sig/gatt/`) - Phase 1
-
-**Purpose**: Pure SIG GATT standard interpretation and parsing
-
-**Responsibilities**:
-
-- Characteristic data parsing with proper types/units
-- Service definition and structure mapping
-- GATT-level SIG standard compliance
-- Device interaction data interpretation
-
-```python
-# Core GATT API - Pure SIG standard translation
-from bluetooth_sig.gatt import CharacteristicRegistry, ServiceRegistry
-
-# Parse raw characteristic data
-parser = CharacteristicRegistry.get_parser("2A19") # Battery Level
-result = parser.decode_value(raw_data)
-# Returns: ParsedCharacteristic(value=85, unit="%", device_class="battery")
-
-# Resolve UUIDs by intelligent name matching
-uuid = CharacteristicRegistry.resolve_uuid("BatteryLevel")
-# Returns: "2A19"
-```
-
-### 2. GAP Layer (`src/bluetooth_sig/gap/`) - Phase 2 (Future)
-
-**Purpose**: SIG standard interpretation for advertisement data
-
-**Responsibilities**:
-
-- Service UUID resolution in advertisements
-- SIG standard compliance validation
-- Advertisement data interpretation
-- Device capability inference from advertisements
-
-```python
-# Future GAP API - Advertisement interpretation
-from bluetooth_sig.gap import AdvertisementInterpreter
-
-# Interpret service UUIDs in advertisements
-services = AdvertisementInterpreter.resolve_services(["180F", "181A"])
-# Returns: [BatteryService, EnvironmentalSensingService]
-```
-
-### 3. Registry Layer (`src/bluetooth_sig/registry/`) - Core Foundation
-
-**Purpose**: Intelligent UUID resolution and SIG standard lookup
-
-**Responsibilities**:
-
-- Multi-stage name parsing and resolution
-- SIG specification data management
-- UUID registry maintenance
-- Cross-layer standard definitions
-
-```python
-# Registry API - Universal SIG standard lookup
-from bluetooth_sig.registry import UUIDRegistry
-
-# Intelligent name resolution
-uuid = UUIDRegistry.resolve("TemperatureCharacteristic")
-# Tries: "TemperatureCharacteristic" â "Temperature" â org.bluetooth format
-name = UUIDRegistry.get_name("2A1C") # Returns: "Temperature Measurement"
-```
-
-## Integration Patterns
-
-### Pattern 1: Pure SIG Translation (Core Use Case)
-
-```python
-from bluetooth_sig.gatt import CharacteristicRegistry
-
-def parse_sensor_reading(char_uuid: str, raw_data: bytes):
- """Pure SIG standard translation - no connection dependencies."""
- parser = CharacteristicRegistry.get_parser(char_uuid)
- if parser:
- return parser.decode_value(raw_data)
- return raw_data # Fallback to raw data
-```
-
-### Pattern 2: With bleak-retry-connector (Recommended for Applications)
-
-```python
-from bleak_retry_connector import establish_connection
-from bleak import BleakClient
-from bluetooth_sig.gatt import CharacteristicRegistry, ServiceRegistry
-
-async def read_device_sensors(address: str):
- """Read and parse device sensors using proven connection management."""
- async with establish_connection(BleakClient, address, timeout=10.0) as client:
- results = {}
-
- for service in await client.get_services():
- if service_info := ServiceRegistry.get_service_info(service.uuid):
- for char in service.characteristics:
- if parser := CharacteristicRegistry.get_parser(char.uuid):
- raw_data = await client.read_gatt_char(char.uuid)
- results[char.uuid] = parser.decode_value(raw_data)
-
- return results
-```
-
-### Pattern 3: With Direct Bleak (Simple Cases)
-
-```python
-from bleak import BleakClient
-from bluetooth_sig.gatt import CharacteristicRegistry
-
-async def simple_characteristic_read(address: str, char_uuid: str):
- """Simple characteristic reading with pure bleak."""
- async with BleakClient(address, timeout=10.0) as client:
- raw_data = await client.read_gatt_char(char_uuid)
- parser = CharacteristicRegistry.get_parser(char_uuid)
- return parser.decode_value(raw_data) if parser else raw_data
-```
-
-### Pattern 4: Integration with bluetooth-data-tools
-
-```python
-from bluetooth_data_tools import parse_advertisement_data
-from bluetooth_sig.gap import AdvertisementInterpreter # Future
-from bluetooth_sig.gatt import ServiceRegistry
-
-async def discover_and_interpret_device(advertisement_data):
- """Combine advertisement parsing with SIG interpretation."""
- # Parse raw advertisement
- adv = parse_advertisement_data(advertisement_data)
-
- # Interpret using SIG standards (future functionality)
- interpreted_services = []
- for service_uuid in adv.service_uuids:
- if service_info := ServiceRegistry.get_service_info(service_uuid):
- interpreted_services.append(service_info)
-
- return {
- 'device_name': adv.local_name,
- 'services': interpreted_services,
- 'capabilities': [s.category for s in interpreted_services]
- }
-```
-
-## Development Phases
-
-### Phase 1: Core GATT Layer (MVP)
-- Basic characteristic and service parsing
-- Registry-driven UUID resolution
-- Integration with bleak/bleak-retry-connector
-- Essential SIG standard characteristics
-
-### Phase 2: GAP Layer Enhancement
-- Advertisement data interpretation
-- Service discovery optimization
-- SIG compliance validation
-- bluetooth-data-tools integration
-
-### Phase 3: Compiled Registry System (Performance Optimization)
-
-**Purpose**: Pre-compiled Python classes for zero-overhead SIG standard access
-
-**Problem**: Runtime YAML parsing overhead and dynamic lookups
-**Solution**: Code generation system that pre-compiles YAML specifications into optimized Python classes
-
-```python
-# Phase 3: Compiled Registry Architecture
-bluetooth-sig/
-âââ src/bluetooth_sig/
-â âââ codegen/ # Code Generation System
-â â âââ compiler.py # YAML-to-Python compiler
-â â âââ templates/ # Jinja2 code templates
-â â â âââ characteristic.py.j2 # Characteristic class template
-â â â âââ service.py.j2 # Service class template
-â â â âââ registry.py.j2 # Static registry template
-â â âââ validators.py # Generated code validation
-â âââ compiled/ # Generated Code (Build Artifact)
-â â âââ __init__.py
-â â âââ characteristics/ # Pre-compiled characteristic classes
-â â â âââ battery_level_2a19.py # class BatteryLevel2A19(BaseCharacteristic)
-â â â âââ temperature_2a1c.py # class Temperature2A1C(BaseCharacteristic)
-â â â âââ humidity_2a6f.py # class Humidity2A6F(BaseCharacteristic)
-â â âââ services/ # Pre-compiled service classes
-â â â âââ battery_service_180f.py # class BatteryService180F(BaseService)
-â â â âââ environmental_181a.py # class EnvironmentalSensing181A(BaseService)
-â â âââ registry.py # Static lookup dictionaries
-â âââ runtime/ # Runtime System (Fallback)
-â âââ loader.py # Dynamic YAML loader (Phase 1)
-â âââ resolver.py # Runtime name resolution
-âââ build_tools/
- âââ compile_sig_database.py # Build script for releases
- âââ validate_generated_code.py # Quality assurance
-```
-
-**Build Process**:
-```bash
-# During release preparation
-python build_tools/compile_sig_database.py \
- --input database/ \
- --output src/bluetooth_sig/compiled/ \
- --validate
-
-# Generates optimized Python classes with:
-# - Zero YAML parsing overhead
-# - Direct memory access to specifications
-# - Type hints for IDE support
-# - Compile-time validation
-```
-
-**Runtime Performance**:
-```python
-# Phase 1: Runtime YAML parsing
-parser = CharacteristicRegistry.get_parser("2A19") # ~1-5ms YAML lookup
-
-# Phase 3: Compiled classes
-from bluetooth_sig.compiled.characteristics import BatteryLevel2A19
-parser = BatteryLevel2A19() # ~0.001ms direct instantiation
-
-# 1000x+ performance improvement for parser instantiation
-# Zero memory overhead for registry lookups
-# Better IDE support with static typing
-```
-
-**Generated Code Example**:
-```python
-# Generated: src/bluetooth_sig/compiled/characteristics/battery_level_2a19.py
-from bluetooth_sig.gatt.base import BaseCharacteristic
-from typing import Dict, Any
-
-class BatteryLevel2A19(BaseCharacteristic):
- """Battery Level - Compiled SIG Standard Implementation."""
-
- UUID = "2A19"
- NAME = "Battery Level"
- UNIT = "%"
- DATA_TYPE = "uint8"
- RANGE_MIN = 0
- RANGE_MAX = 100
-
- def decode_value(self, data: bytes) -> Dict[str, Any]:
- """Parse battery level with compile-time optimized logic."""
- if len(data) != 1:
- raise ValueError("Battery Level requires exactly 1 byte")
-
- value = data[0]
- if value > 100:
- raise ValueError("Battery Level must be 0-100%")
-
- return {
- "value": value,
- "unit": "%",
- "device_class": "battery"
- }
-```
-
-**Distribution Strategy**:
-```python
-# PyPI package includes both modes
-import bluetooth_sig
-
-# Production mode: Use compiled classes (default)
-from bluetooth_sig import get_characteristic_parser
-parser = get_characteristic_parser("2A19") # Uses compiled BatteryLevel2A19
-
-# Development mode: Use runtime YAML (optional)
-from bluetooth_sig.runtime import CharacteristicRegistry
-parser = CharacteristicRegistry.get_parser("2A19") # Dynamic YAML parsing
-```
-
-**Benefits of Compiled Approach**:
-
-1. **Performance**: 1000x+ faster parser instantiation
-2. **Memory**: Zero YAML parsing overhead in production
-3. **IDE Support**: Full type hints and autocompletion
-4. **Validation**: Compile-time specification checking
-5. **Distribution**: Single wheel with pre-compiled standards
-6. **Backwards Compatibility**: Runtime mode still available for development
-
-**Release Workflow**:
-```bash
-# 1. Update SIG database submodule
-git submodule update --remote database/
-
-# 2. Compile specifications to Python classes
-python build_tools/compile_sig_database.py
-
-# 3. Validate generated code
-python build_tools/validate_generated_code.py
-
-# 4. Package with compiled classes
-python -m build
-
-# 5. Publish to PyPI with optimized registry
-twine upload dist/bluetooth_sig-*.whl
-```
-
-This compiled approach transforms the library from a runtime YAML processor into a compile-time optimized SIG standard implementation, providing production-grade performance while maintaining development flexibility.
-
-## Key Architectural Decisions
-
-### â
Pure SIG Standards Library
-
-- **Zero connection dependencies** - focuses purely on SIG standard interpretation
-- **Framework agnostic** - works with any connection library
-- **Reusable across platforms** - pure Python implementation
-
-### â
Layered Architecture
-
-- **GATT Layer**: Device interaction and characteristic parsing
-- **GAP Layer**: Advertisement interpretation (future)
-- **Registry Layer**: Universal SIG standard lookup and resolution
-
-### â
Registry-Driven Design
-
-- **Intelligent UUID resolution** with multi-stage name parsing
-- **Automatic characteristic discovery** based on SIG standards
-- **Extensible parser registration** system for custom implementations
-
-### â
Integration Flexibility
-
-- **Works with any BLE library** (bleak, bleak-retry-connector, custom)
-- **Optional enhancement** for existing tools (bluetooth-data-tools)
-- **Framework ready** for IoT platforms, applications, and integrations
-
-## Package Distribution
-
-### Core Package: `bluetooth-sig`
-
-```toml
-[build-system]
-requires = ["setuptools>=61.0", "wheel"]
-build-backend = "setuptools.build_meta"
-
-[project]
-name = "bluetooth-sig"
-description = "Python library for Bluetooth SIG standard interpretation and parsing"
-readme = "README.md"
-requires-python = ">=3.8"
-license = {text = "MIT"}
-authors = [
- {name = "Your Name", email = "your.email@example.com"},
-]
-classifiers = [
- "Development Status :: 4 - Beta",
- "Intended Audience :: Developers",
- "License :: OSI Approved :: MIT License",
- "Operating System :: OS Independent",
- "Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.9",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3.11",
- "Programming Language :: Python :: 3.12",
- "Topic :: Software Development :: Libraries :: Python Modules",
- "Topic :: System :: Hardware",
- "Topic :: Communications",
-]
-dependencies = [
- "pyyaml>=6.0", # SIG specification data parsing
-]
-dynamic = ["version"]
-
-[project.optional-dependencies]
-# Integration examples and testing
-integration = [
- "bleak>=0.20.0",
- "bleak-retry-connector>=3.0.0",
-]
-
-# Development dependencies
-dev = [
- "pytest>=7.0.0",
- "pytest-asyncio>=0.21.0",
- "pytest-cov>=4.0.0",
- "black>=22.0.0",
- "isort>=5.0.0",
- "flake8>=5.0.0",
- "mypy>=1.0.0",
- "pre-commit>=2.20.0",
-]
-
-# Documentation
-docs = [
- "mkdocs>=1.4.0",
- "mkdocs-material>=8.0.0",
- "mkdocstrings[python]>=0.20.0",
-]
-
-[project.urls]
-Homepage = "https://github.com/yourusername/bluetooth-sig"
-Documentation = "https://bluetooth-sig.readthedocs.io"
-Repository = "https://github.com/yourusername/bluetooth-sig"
-Issues = "https://github.com/yourusername/bluetooth-sig/issues"
-Changelog = "https://github.com/yourusername/bluetooth-sig/blob/main/CHANGELOG.md"
-
-[tool.setuptools.dynamic]
-version = {attr = "bluetooth_sig.__version__"}
-
-[tool.setuptools.packages.find]
-where = ["src"]
-
-[tool.pytest.ini_options]
-testpaths = ["tests"]
-addopts = "-ra -q --strict-markers --strict-config"
-markers = [
- "slow: marks tests as slow (deselect with '-m \"not slow\"')",
- "integration: marks tests as integration tests",
-]
-
-[tool.black]
-target-version = ["py38"]
-line-length = 88
-
-[tool.isort]
-profile = "black"
-
-[tool.mypy]
-python_version = "3.8"
-warn_return_any = true
-warn_unused_configs = true
-disallow_untyped_defs = true
-```
-
-### Installation Options
-
-```bash
-# Core SIG standards library only
-pip install bluetooth-sig
-
-# With integration examples for development
-pip install bluetooth-sig[integration]
-
-# For development
-pip install bluetooth-sig[dev]
-
-# Full installation with docs
-pip install bluetooth-sig[integration,dev,docs]
-
-# Integration with ecosystem libraries (user choice)
-pip install bluetooth-sig bleak-retry-connector # Recommended
-pip install bluetooth-sig bleak # Basic
-pip install bluetooth-sig bluetooth-data-tools # With advertisement parsing
-```
-
-## Benefits of This Architecture
-
-1. **ðŊ Focused Value Proposition**: Pure SIG standard expertise and interpretation
-2. **ð Universal Integration**: Works with any BLE connection library or framework
-3. **ðïļ Clean Architecture**: Clear separation between standards and connectivity
-4. **ð§Š Comprehensive Testing**: Real device validation through integration tests
-5. **ðĶ Lightweight Core**: Zero connection dependencies, pure standards implementation
-6. **ð Future Proof**: Extensible to new SIG standards and connection technologies
-7. **ð Ecosystem Ready**: Designed for integration with existing Bluetooth libraries
-
-This architecture makes `bluetooth-sig` the definitive Python library for Bluetooth SIG standard interpretation while leveraging the ecosystem's best connection management and data parsing solutions.
diff --git a/docs/PERFORMANCE.md b/docs/PERFORMANCE.md
deleted file mode 100644
index f6ec0123..00000000
--- a/docs/PERFORMANCE.md
+++ /dev/null
@@ -1,345 +0,0 @@
-# Performance Profiling and Optimization Guide
-
-This guide covers performance characteristics, profiling tools, and optimization strategies for the Bluetooth SIG library.
-
-## Quick Start
-
-### Running Benchmarks
-
-Run the comprehensive benchmark suite:
-
-```bash
-python examples/benchmarks/parsing_performance.py
-```
-
-Run with logging enabled to see detailed parsing information:
-
-```bash
-python examples/benchmarks/parsing_performance.py --log-level=debug
-```
-
-### Enabling Logging in Your Application
-
-```python
-import logging
-from bluetooth_sig import BluetoothSIGTranslator
-
-# Configure logging - can be set to DEBUG, INFO, WARNING, ERROR
-logging.basicConfig(
- level=logging.DEBUG,
- format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
-)
-
-# Or configure just the bluetooth_sig logger
-logging.getLogger("bluetooth_sig.core.translator").setLevel(logging.DEBUG)
-
-translator = BluetoothSIGTranslator()
-result = translator.parse_characteristic("2A19", bytes([100]))
-# Logs: "Parsing characteristic UUID=2A19, data_len=1"
-# Logs: "Found parser for UUID=2A19: BatteryLevelCharacteristic"
-# Logs: "Successfully parsed Battery Level: 100"
-```
-
-## Profiling Utilities
-
-The library includes profiling utilities in `bluetooth_sig.utils.profiling`:
-
-### Timer Context Manager
-
-```python
-from bluetooth_sig.utils.profiling import timer
-
-with timer("parse operation") as t:
- result = translator.parse_characteristic("2A19", data)
-
-print(f"Parse took {t['elapsed']:.4f} seconds")
-```
-
-### Benchmark Function
-
-```python
-from bluetooth_sig.utils.profiling import benchmark_function
-
-result = benchmark_function(
- lambda: translator.parse_characteristic("2A19", data),
- iterations=10000,
- operation="Battery Level parsing"
-)
-
-print(result) # Shows avg, min, max times and throughput
-```
-
-### Compare Implementations
-
-```python
-from bluetooth_sig.utils.profiling import compare_implementations, format_comparison
-
-results = compare_implementations(
- {
- "manual": lambda: manual_parse(data),
- "sig_lib": lambda: translator.parse_characteristic("2A19", data)
- },
- iterations=10000
-)
-
-print(format_comparison(results, baseline="manual"))
-```
-
-### Profiling Session
-
-Track multiple benchmarks in a session:
-
-```python
-from bluetooth_sig.utils.profiling import ProfilingSession
-
-session = ProfilingSession(name="My Application Benchmarks")
-
-# Add results from various benchmarks
-session.add_result(result1)
-session.add_result(result2)
-
-print(session) # Pretty-printed summary of all results
-```
-
-## Performance Characteristics
-
-### Parsing Latency
-
-Based on benchmark results with 10,000 iterations:
-
-| Characteristic Type | Complexity | Avg Latency | Throughput |
-|-------------------|------------|-------------|------------|
-| Battery Level | Simple (1 byte) | 0.01ms | ~100k ops/sec |
-| Temperature | Moderate (2 bytes) | 0.02ms | ~48k ops/sec |
-| Heart Rate | Complex (flags) | 0.07ms | ~14k ops/sec |
-
-### Batch Processing
-
-Batch parsing (`parse_characteristics`) has minimal overhead:
-- Individual parsing: 0.10ms per characteristic
-- Batch parsing: 0.11ms per characteristic (11% overhead)
-- Batch overhead is amortized - better for 10+ characteristics
-
-### Real-World Performance
-
-For a health thermometer device sending notifications every 1 second:
-- Parse latency: ~0.03ms
-- CPU usage: 0.003% per notification
-- Could handle 30,000+ concurrent devices on a single thread
-
-### Logging Overhead
-
-Logging impact on performance:
-- **Disabled** (WARNING level): baseline performance
-- **INFO level**: ~5-10% overhead
-- **DEBUG level**: ~10-20% overhead
-
-**Recommendation**: Use WARNING level in production, DEBUG only for troubleshooting.
-
-## Optimization Strategies
-
-### 1. High-Throughput Applications
-
-For applications processing many notifications per second:
-
-```python
-# â
Good: Batch processing
-sensor_data = {
- "2A19": battery_data,
- "2A6E": temp_data,
- "2A6F": humidity_data,
-}
-results = translator.parse_characteristics(sensor_data)
-
-# â Avoid: Processing one at a time in a tight loop
-for uuid, data in sensor_data.items():
- result = translator.parse_characteristic(uuid, data)
-```
-
-### 2. Low-Latency Applications
-
-For real-time applications requiring minimal latency:
-
-```python
-# â
Good: Reuse translator instance
-translator = BluetoothSIGTranslator()
-# Use the same instance for all parses
-
-# â Avoid: Creating new translator for each parse
-result = BluetoothSIGTranslator().parse_characteristic(uuid, data)
-```
-
-### 3. Memory Optimization
-
-For applications handling many devices:
-
-```python
-translator = BluetoothSIGTranslator()
-
-# Process device data...
-
-# Periodically clear cached services if tracking many devices
-translator.clear_services()
-```
-
-### 4. Caching Characteristic Info
-
-If repeatedly parsing the same characteristic types:
-
-```python
-# Cache characteristic info at startup
-char_info = translator.get_characteristic_info("2A19")
-
-# Use cached info to validate before parsing
-if char_info:
- result = translator.parse_characteristic("2A19", data)
-```
-
-## Hot Code Paths
-
-Based on profiling, these are the most frequently executed code paths:
-
-1. **`CharacteristicRegistry.create_characteristic`** - UUID lookup
- - Optimize by minimizing unique UUID types
- - Cache characteristic instances if possible
-
-2. **`Characteristic.parse_value`** - Parsing logic
- - Most time spent here is unavoidable (actual parsing)
- - Consider manual parsing for ultra-low-latency requirements
-
-3. **Context building** - In batch operations
- - Overhead is minimal but scales with batch size
- - Use context only when needed (device info, cross-char references)
-
-## Profiling Your Application
-
-### Example: Profile Device Connection Flow
-
-```python
-from bluetooth_sig.utils.profiling import ProfilingSession, benchmark_function
-
-session = ProfilingSession(name="Device Connection Profile")
-
-# Profile discovery
-discovery_result = benchmark_function(
- lambda: discover_devices(),
- iterations=10,
- operation="Device discovery"
-)
-session.add_result(discovery_result)
-
-# Profile connection
-connect_result = benchmark_function(
- lambda: connect_to_device(device_id),
- iterations=10,
- operation="Device connection"
-)
-session.add_result(connect_result)
-
-# Profile parsing
-parse_result = benchmark_function(
- lambda: translator.parse_characteristics(char_data),
- iterations=100,
- operation="Parse all characteristics"
-)
-session.add_result(parse_result)
-
-# Print comprehensive report
-print(session)
-```
-
-## Logging Levels
-
-### DEBUG
-
-Most verbose - shows every parse operation:
-
-```
-2025-10-01 10:00:00,123 - bluetooth_sig.core.translator - DEBUG - Parsing characteristic UUID=2A19, data_len=1
-2025-10-01 10:00:00,124 - bluetooth_sig.core.translator - DEBUG - Found parser for UUID=2A19: BatteryLevelCharacteristic
-2025-10-01 10:00:00,125 - bluetooth_sig.core.translator - DEBUG - Successfully parsed Battery Level: 100
-```
-
-**Use for**: Development, troubleshooting parsing issues
-
-### INFO
-
-High-level information about operations:
-
-```
-2025-10-01 10:00:00,123 - bluetooth_sig.core.translator - INFO - No parser available for UUID=unknown-uuid
-```
-
-**Use for**: Monitoring, identifying missing parsers
-
-### WARNING
-
-Parse failures and issues:
-
-```
-2025-10-01 10:00:00,123 - bluetooth_sig.core.translator - WARNING - Parse failed for Temperature: Data too short
-```
-
-**Use for**: Production monitoring, alerting
-
-### ERROR
-
-Critical errors only:
-
-**Use for**: Production (minimal overhead)
-
-## Benchmark Results
-
-The comprehensive benchmark (`examples/benchmarks/parsing_performance.py`) provides:
-
-1. **Single characteristic parsing** - Compare manual vs library parsing
-2. **Batch parsing** - Evaluate batch vs individual parsing
-3. **UUID resolution** - Measure lookup performance
-4. **Real-world scenario** - Simulated device interaction
-
-### Sample Output
-
-```
-Profile: Parsing Performance Benchmark
-Total operations measured: 6
-
-Average performance across all tests:
- Latency: 0.0425ms per operation
- Throughput: 47,641 operations/sec
-
-OPTIMIZATION RECOMMENDATIONS:
-1. Use batch parsing when possible
-2. Library adds minimal overhead (<0.1ms for simple characteristics)
-3. Reuse translator instances
-4. Enable logging only for debugging
-```
-
-## When to Use Manual Parsing
-
-Consider manual parsing if:
-
-1. **Ultra-low latency required** - Library adds ~0.01-0.07ms overhead
-2. **Simple characteristic** - Battery level (1 byte) is trivial to parse manually
-3. **Custom format** - Non-standard or proprietary characteristics
-
-Otherwise, use the library for:
-- **Standards compliance** - Handles all SIG specification details
-- **Maintainability** - No need to understand binary formats
-- **Robustness** - Built-in validation and error handling
-- **Features** - Units, types, timestamps, status codes
-
-## Contributing Optimizations
-
-If you identify performance bottlenecks:
-
-1. Run the benchmark: `python examples/benchmarks/parsing_performance.py`
-2. Use profiling tools to identify hot spots
-3. Propose optimizations with benchmark comparisons
-4. Submit PR with before/after performance data
-
-## See Also
-
-- [`examples/benchmarks/parsing_performance.py`](../examples/benchmarks/parsing_performance.py) - Comprehensive benchmark
-- [`src/bluetooth_sig/utils/profiling.py`](../src/bluetooth_sig/utils/profiling.py) - Profiling utilities API
-- [`tests/test_profiling.py`](../tests/test_profiling.py) - Profiling utility tests
-- [`tests/test_logging.py`](../tests/test_logging.py) - Logging functionality tests
diff --git a/docs/README.md b/docs/README.md
deleted file mode 100644
index e991f5ec..00000000
--- a/docs/README.md
+++ /dev/null
@@ -1,107 +0,0 @@
-# Documentation
-
-This directory contains the source files for the Bluetooth SIG Standards Library documentation.
-
-## Building Documentation
-
-### Local Build
-
-```bash
-# Install documentation dependencies
-pip install -e ".[docs]"
-
-# Build documentation
-mkdocs build
-
-# Serve documentation locally with live reload
-mkdocs serve
-```
-
-Then visit http://127.0.0.1:8000 in your browser.
-
-## Documentation Structure
-
-- `index.md` - Landing page
-- `installation.md` - Installation instructions
-- `quickstart.md` - Quick start guide
-- `usage.md` - Comprehensive usage guide
-- `why-use.md` - Why use this library
-- `what-it-solves.md` - Problems this library solves
-- `what-it-does-not-solve.md` - What's out of scope
-- `architecture.md` - Architecture overview
-- `testing.md` - Testing guide
-- `api/` - API reference documentation
-- `guides/` - How-to guides
-
-## Coverage Integration
-
-The test coverage report is automatically integrated into the documentation:
-
-- Coverage is generated by pytest-cov during CI
-- The HTML coverage report is placed in the `site/coverage/` directory
-- Access the coverage report at: `/coverage/` in the deployed documentation
-
-## Deployment
-
-Documentation is automatically deployed to GitHub Pages when changes are pushed to the `main` branch via the `.github/workflows/test-coverage.yml` workflow.
-
-The workflow:
-1. Runs tests and generates coverage
-2. Builds documentation with MkDocs
-3. Combines coverage report with documentation
-4. Deploys to GitHub Pages
-
-## Writing Documentation
-
-### Style Guide
-
-- Use clear, concise language
-- Include code examples
-- Add type hints to code examples
-- Use admonitions for important notes
-- Link to related documentation
-
-### Code Examples
-
-Always include complete, runnable examples:
-
-```python
-from bluetooth_sig.core import BluetoothSIGTranslator
-
-translator = BluetoothSIGTranslator()
-result = translator.parse_characteristic_data("2A19", bytearray([85]))
-print(f"Battery: {result.value}%")
-```
-
-### API Documentation
-
-API documentation is auto-generated from docstrings using mkdocstrings. Follow the Google docstring style:
-
-```python
-def example_function(param: str) -> int:
- """One-line summary.
-
- Detailed description of the function.
-
- Args:
- param: Description of parameter
-
- Returns:
- Description of return value
-
- Raises:
- ValueError: When something goes wrong
-
- Examples:
- >>> example_function("test")
- 42
- """
- return 42
-```
-
-## Tools
-
-- **MkDocs**: Documentation generator
-- **Material for MkDocs**: Theme
-- **mkdocstrings**: API documentation from docstrings
-- **pymdown-extensions**: Additional markdown features
diff --git a/docs/api/core.md b/docs/api/core.md
index 39f811f5..04cf6ca3 100644
--- a/docs/api/core.md
+++ b/docs/api/core.md
@@ -1,13 +1,14 @@
# Core API Reference
-The core API provides the main entry point for using the Bluetooth SIG Standards Library.
+The core API provides the main entry point for using the Bluetooth SIG Standards
+Library.
## BluetoothSIGTranslator
::: bluetooth_sig.core.BluetoothSIGTranslator
- options:
- show_root_heading: true
- heading_level: 3
+options:
+show_root_heading: true
+heading_level: 3
## Quick Reference
@@ -19,12 +20,11 @@ from bluetooth_sig.core import BluetoothSIGTranslator
translator = BluetoothSIGTranslator()
# Resolve UUID to get information
-service_info = translator.resolve_uuid("180F")
+service_info = translator.resolve_by_uuid("180F")
print(service_info.name) # "Battery Service"
-print(service_info.type) # "service"
# Resolve characteristic
-char_info = translator.resolve_uuid("2A19")
+char_info = translator.resolve_by_uuid("2A19")
print(char_info.name) # "Battery Level"
```
@@ -32,10 +32,10 @@ print(char_info.name) # "Battery Level"
```python
# Resolve name to UUID
-battery_service = translator.resolve_name("Battery Service")
+battery_service = translator.resolve_by_name("Battery Service")
print(battery_service.uuid) # "180F"
-battery_level = translator.resolve_name("Battery Level")
+battery_level = translator.resolve_by_name("Battery Level")
print(battery_level.uuid) # "2A19"
```
@@ -43,11 +43,11 @@ print(battery_level.uuid) # "2A19"
```python
# Parse characteristic data
-battery_data = translator.parse_characteristic_data("2A19", bytearray([85]))
+battery_data = translator.parse_characteristic("2A19", bytearray([85]))
print(f"Battery: {battery_data.value}%") # Battery: 85%
# Parse temperature
-temp_data = translator.parse_characteristic_data("2A6E", bytearray([0x64, 0x09]))
+temp_data = translator.parse_characteristic("2A6E", bytearray([0x64, 0x09]))
print(f"Temperature: {temp_data.value}°C") # Temperature: 24.36°C
```
@@ -63,7 +63,7 @@ from bluetooth_sig.gatt.exceptions import (
)
try:
- result = translator.parse_characteristic_data("2A19", data)
+ result = translator.parse_characteristic("2A19", data)
except UUIDResolutionError:
print("Unknown UUID")
except InsufficientDataError:
diff --git a/docs/api/gatt.md b/docs/api/gatt.md
index cf0790b6..533c2fe4 100644
--- a/docs/api/gatt.md
+++ b/docs/api/gatt.md
@@ -1,13 +1,14 @@
# GATT Layer API Reference
-The GATT layer provides the fundamental building blocks for Bluetooth characteristic parsing.
+The GATT layer provides the fundamental building blocks for Bluetooth characteristic
+parsing.
## Overview
The GATT layer consists of:
- **Characteristic parsers** - 70+ implementations for standard characteristics
-- **Service definitions** - Organize characteristics into services
+- **Service definitions** - Organize characteristics into services
- **Validation logic** - Ensure data integrity
- **Exception types** - Clear error reporting
diff --git a/docs/api/registry.md b/docs/api/registry.md
index 60bc9a31..49fe1a1a 100644
--- a/docs/api/registry.md
+++ b/docs/api/registry.md
@@ -33,11 +33,11 @@ from bluetooth_sig.core import BluetoothSIGTranslator
translator = BluetoothSIGTranslator()
# Service name to UUID
-service = translator.resolve_name("Battery Service")
+service = translator.resolve_by_name("Battery Service")
print(service.uuid) # "180F"
# Characteristic name to UUID
-char = translator.resolve_name("Battery Level")
+char = translator.resolve_by_name("Battery Level")
print(char.uuid) # "2A19"
```
diff --git a/docs/architecture.md b/docs/architecture.md
index d2f4ac32..5bacc4bf 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -1,20 +1,21 @@
# Architecture Overview
-Understanding the architecture helps you make the most of the Bluetooth SIG Standards Library.
+Understanding the architecture helps you make the most of the Bluetooth SIG Standards
+Library.
## Design Philosophy
The library follows these core principles:
1. **Standards First** - Built directly from Bluetooth SIG specifications
-2. **Separation of Concerns** - Parse data, don't manage connections
-3. **Type Safety** - Strong typing throughout
-4. **Framework Agnostic** - Works with any BLE library
-5. **Zero Side Effects** - Pure functions for parsing
+1. **Separation of Concerns** - Parse data, don't manage connections
+1. **Type Safety** - Strong typing throughout
+1. **Framework Agnostic** - Works with any BLE library
+1. **Zero Side Effects** - Pure functions for parsing
## High-Level Architecture
-```
+```text
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Your Application â
â (GUI, Business Logic, State) â
@@ -58,12 +59,14 @@ The library follows these core principles:
**Key Class**: `BluetoothSIGTranslator`
**Responsibilities**:
+
- UUID â Name resolution
- Characteristic data parsing
- Service information lookup
- Type conversion and validation
**Example Usage**:
+
```python
from bluetooth_sig.core import BluetoothSIGTranslator
@@ -76,7 +79,8 @@ result = translator.parse_characteristic_data("2A19", data)
**Purpose**: Bluetooth GATT specification implementation
**Structure**:
-```
+
+```text
gatt/
âââ characteristics/ # 70+ characteristic implementations
â âââ base.py # Base characteristic class
@@ -94,6 +98,7 @@ gatt/
**Key Components**:
#### Base Characteristic
+
```python
from bluetooth_sig.gatt.characteristics.base import BaseCharacteristic
@@ -109,6 +114,7 @@ class BatteryLevelCharacteristic(BaseCharacteristic):
```
#### Characteristic Features
+
- **Length validation** - Ensures correct data size
- **Range validation** - Enforces spec limits
- **Type conversion** - Raw bytes â typed values
@@ -120,25 +126,28 @@ class BatteryLevelCharacteristic(BaseCharacteristic):
**Purpose**: UUID and name resolution based on official Bluetooth SIG registry
**Structure**:
-```
+
+```text
registry/
âââ yaml_cross_reference.py # YAML registry loader
âââ uuid_registry.py # UUID resolution
âââ name_resolver.py # Name-based lookup
```
-**Data Source**:
+**Data Source**:
+
- Official Bluetooth SIG YAML files (via git submodule)
- Located in `bluetooth_sig/assigned_numbers/uuids/`
**Capabilities**:
+
```python
# UUID to information
info = registry.get_characteristic_info("2A19")
# Returns: CharacteristicInfo(uuid="2A19", name="Battery Level")
# Name to UUID
-uuid = registry.resolve_name("Battery Level")
+uuid = registry.resolve_by_name("Battery Level")
# Returns: "2A19"
# Handles both short and long UUID formats
@@ -153,6 +162,7 @@ info = registry.get_service_info("0000180f-0000-1000-8000-00805f9b34fb")
**Key Components**:
#### Enums
+
```python
from bluetooth_sig.types.gatt_enums import (
CharacteristicName,
@@ -165,6 +175,7 @@ ServiceName.BATTERY_SERVICE # "Battery Service"
```
#### Data Structures
+
```python
from dataclasses import dataclass
@@ -178,7 +189,7 @@ class BatteryLevelData:
### Parsing Flow
-```
+```text
1. Raw BLE Data
â
2. BluetoothSIGTranslator.parse_characteristic_data()
@@ -257,14 +268,14 @@ def decode_value(self, data: bytearray) -> int:
# Layer 1: Structure validation
if len(data) != 1:
raise InsufficientDataError(...)
-
+
# Layer 2: Data extraction
value = int(data[0])
-
+
# Layer 3: Domain validation
if not 0 <= value <= 100:
raise ValueRangeError(...)
-
+
return value
```
@@ -282,7 +293,7 @@ class MyCustomCharacteristic(BaseCharacteristic):
uuid=BluetoothUUID("XXXX"),
name="My Custom Characteristic"
)
-
+
def decode_value(self, data: bytearray) -> int:
# Your parsing logic
return int(data[0])
@@ -297,7 +308,7 @@ class MyCustomService(BaseService):
def __init__(self):
super().__init__()
self.my_char = MyCustomCharacteristic()
-
+
@property
def characteristics(self) -> dict:
return {"my_char": self.my_char}
@@ -306,16 +317,19 @@ class MyCustomService(BaseService):
## Testing Architecture
### Unit Tests
+
- Individual characteristic parsing
- Registry resolution
- Validation logic
### Integration Tests
+
- Full parsing flow
- Multiple characteristics
- Error handling
### Example
+
```python
def test_battery_parsing():
translator = BluetoothSIGTranslator()
@@ -326,12 +340,14 @@ def test_battery_parsing():
## Performance Considerations
### Optimizations
+
- **Registry caching** - UUID lookups cached after first resolution
- **Minimal allocations** - Direct parsing without intermediate objects
- **Type hints** - Enable JIT optimization
- **Lazy loading** - Characteristics loaded on-demand
### Benchmarks
+
- UUID resolution: ~10 Ξs
- Simple characteristic parse: ~50 Ξs
- Complex characteristic parse: ~200 Ξs
@@ -339,21 +355,25 @@ def test_battery_parsing():
## Architectural Benefits
### 1. Maintainability
+
- Clear separation of concerns
- Each characteristic is independent
- Easy to add new characteristics
### 2. Testability
+
- Pure functions (no side effects)
- Easy to mock
- No hardware required for testing
### 3. Flexibility
+
- Framework agnostic
- Platform independent
- Extensible design
### 4. Type Safety
+
- Full type hints
- Runtime validation
- Compile-time checking (mypy)
diff --git a/docs/github-readme.md b/docs/github-readme.md
new file mode 120000
index 00000000..32d46ee8
--- /dev/null
+++ b/docs/github-readme.md
@@ -0,0 +1 @@
+../README.md
\ No newline at end of file
diff --git a/docs/guides/adding-characteristics.md b/docs/guides/adding-characteristics.md
index 54ba4383..46c0c762 100644
--- a/docs/guides/adding-characteristics.md
+++ b/docs/guides/adding-characteristics.md
@@ -7,8 +7,8 @@ Learn how to extend the library with custom or newly standardized characteristic
You might need to add a characteristic when:
1. A new Bluetooth SIG standard characteristic is released
-2. You're working with a vendor-specific characteristic
-3. You need custom parsing for a specific use case
+1. You're working with a vendor-specific characteristic
+1. You need custom parsing for a specific use case
## Basic Structure
@@ -20,19 +20,19 @@ from bluetooth_sig.gatt.exceptions import InsufficientDataError, ValueRangeError
class MyCharacteristic(BaseCharacteristic):
"""My Custom Characteristic (UUID: XXXX).
-
+
Specification: [Link to specification if available]
"""
-
+
def decode_value(self, data: bytearray) -> YourReturnType:
"""Decode characteristic data.
-
+
Args:
data: Raw bytes from BLE characteristic
-
+
Returns:
Parsed value in appropriate type
-
+
Raises:
InsufficientDataError: If data is too short
ValueRangeError: If value is out of range
@@ -42,14 +42,14 @@ class MyCharacteristic(BaseCharacteristic):
raise InsufficientDataError(
f"My Characteristic requires at least {expected_length} bytes"
)
-
+
# 2. Parse data
value = parse_logic_here(data)
-
+
# 3. Validate range
if not is_valid(value):
raise ValueRangeError(f"Value {value} is out of range")
-
+
# 4. Return typed result
return value
```
@@ -66,26 +66,26 @@ from bluetooth_sig.types.uuid import BluetoothUUID
class LightLevelCharacteristic(BaseCharacteristic):
"""Light Level characteristic.
-
+
Reports ambient light level as a percentage (0-100%).
-
+
Format:
- 1 byte: uint8
- Range: 0-100
- Unit: percentage
"""
-
+
_info = CharacteristicInfo(
uuid=BluetoothUUID("ABCD"), # Your custom UUID
name="Light Level"
)
-
+
def decode_value(self, data: bytearray) -> int:
"""Decode light level.
-
+
Args:
data: Raw bytes (1 byte expected)
-
+
Returns:
Light level percentage (0-100)
"""
@@ -94,18 +94,18 @@ class LightLevelCharacteristic(BaseCharacteristic):
raise InsufficientDataError(
f"Light Level requires exactly 1 byte, got {len(data)}"
)
-
+
# Parse
value = int(data[0])
-
+
# Validate range
if not 0 <= value <= 100:
raise ValueRangeError(
f"Light level must be 0-100%, got {value}%"
)
-
+
return value
-
+
@property
def unit(self) -> str:
"""Return the unit for this characteristic."""
@@ -130,15 +130,15 @@ class SensorReading:
class MultiSensorCharacteristic(BaseCharacteristic):
"""Multi-sensor characteristic with multiple fields."""
-
+
_info = CharacteristicInfo(
uuid=BluetoothUUID("WXYZ"),
name="Multi Sensor"
)
-
+
def decode_value(self, data: bytearray) -> SensorReading:
"""Decode multi-field sensor data.
-
+
Format:
Bytes 0-1: Temperature (sint16, 0.01°C)
Bytes 2-3: Humidity (uint16, 0.01%)
@@ -150,23 +150,23 @@ class MultiSensorCharacteristic(BaseCharacteristic):
raise InsufficientDataError(
f"Multi Sensor requires 16 bytes, got {len(data)}"
)
-
+
# Parse temperature
temp_raw = int.from_bytes(data[0:2], byteorder='little', signed=True)
temperature = temp_raw * 0.01
-
+
# Parse humidity
hum_raw = int.from_bytes(data[2:4], byteorder='little', signed=False)
humidity = hum_raw * 0.01
-
+
# Parse pressure
press_raw = int.from_bytes(data[4:8], byteorder='little', signed=False)
pressure = press_raw * 0.1
-
+
# Parse timestamp
ts_raw = int.from_bytes(data[8:16], byteorder='little', signed=False)
timestamp = datetime.fromtimestamp(ts_raw)
-
+
return SensorReading(
temperature=temperature,
humidity=humidity,
@@ -185,40 +185,43 @@ from bluetooth_sig.gatt.exceptions import InsufficientDataError, ValueRangeError
class TestLightLevelCharacteristic:
"""Test Light Level characteristic."""
-
+
def test_valid_value(self):
"""Test valid light level."""
char = LightLevelCharacteristic()
result = char.decode_value(bytearray([50]))
assert result == 50
-
+
def test_boundary_values(self):
"""Test boundary values."""
char = LightLevelCharacteristic()
assert char.decode_value(bytearray([0])) == 0
assert char.decode_value(bytearray([100])) == 100
-
+
def test_insufficient_data(self):
"""Test error on insufficient data."""
char = LightLevelCharacteristic()
with pytest.raises(InsufficientDataError):
char.decode_value(bytearray([]))
-
+
def test_out_of_range(self):
"""Test error on out-of-range value."""
char = LightLevelCharacteristic()
with pytest.raises(ValueRangeError):
- char.decode_value(bytearray([101]))
+ char.decode_value(
+ bytearray([101])
+ )
```
## Contributing Back
-If you've added a standard Bluetooth SIG characteristic, consider contributing it back:
+If you've added a standard Bluetooth SIG characteristic,
+consider contributing it back:
1. Ensure your implementation follows the official specification
-2. Add comprehensive tests
-3. Add proper docstrings
-4. Open a pull request
+1. Add comprehensive tests
+1. Add proper docstrings
+1. Open a pull request
See [Contributing Guide](../contributing.md) for details.
diff --git a/docs/guides/ble-integration.md b/docs/guides/ble-integration.md
index a0ef0d74..45696a11 100644
--- a/docs/guides/ble-integration.md
+++ b/docs/guides/ble-integration.md
@@ -1,6 +1,7 @@
# BLE Integration Guide
-Learn how to integrate bluetooth-sig with your preferred BLE connection library.
+Learn how to integrate bluetooth-sig with your preferred BLE connection
+library.
## Philosophy
@@ -9,13 +10,14 @@ The bluetooth-sig library follows a clean separation of concerns:
- **BLE Library** â Device connection, I/O operations
- **bluetooth-sig** â Standards interpretation, data parsing
-This design lets you choose the best BLE library for your platform while using bluetooth-sig for consistent data parsing.
+This design lets you choose the best BLE library for your platform while using
+bluetooth-sig for consistent data parsing.
## Integration with bleak
[bleak](https://github.com/hbldh/bleak) is a cross-platform async BLE library (recommended).
-### Installation
+### bleak Installation
```bash
pip install bluetooth-sig bleak
@@ -30,21 +32,23 @@ from bluetooth_sig.core import BluetoothSIGTranslator
async def main():
translator = BluetoothSIGTranslator()
-
+
# Scan for devices
devices = await BleakScanner.discover()
for device in devices:
print(f"Found: {device.name} ({device.address})")
-
+
# Connect to device
address = "AA:BB:CC:DD:EE:FF"
async with BleakClient(address) as client:
# Read battery level
raw_data = await client.read_gatt_char("2A19")
-
+
# Parse with bluetooth-sig
- result = translator.parse_characteristic_data("2A19", raw_data)
- print(f"Battery: {result.value}%")
+ result = translator.parse_characteristic_data("2A19", raw_data)
+ print(
+ f"Battery: {result.value}%"
+ )
asyncio.run(main())
```
@@ -54,7 +58,7 @@ asyncio.run(main())
```python
async def read_sensor_data(address: str):
translator = BluetoothSIGTranslator()
-
+
async with BleakClient(address) as client:
# Define characteristics to read
characteristics = {
@@ -62,7 +66,7 @@ async def read_sensor_data(address: str):
"Temperature": "2A6E",
"Humidity": "2A6F",
}
-
+
# Read and parse
for name, uuid in characteristics.items():
try:
@@ -79,7 +83,7 @@ async def read_sensor_data(address: str):
def notification_handler(sender, data):
"""Handle BLE notifications."""
translator = BluetoothSIGTranslator()
-
+
# Parse the notification data
uuid = str(sender.uuid)
result = translator.parse_characteristic_data(uuid, data)
@@ -89,25 +93,26 @@ async def subscribe_to_notifications(address: str):
async with BleakClient(address) as client:
# Subscribe to heart rate notifications
await client.start_notify("2A37", notification_handler)
-
+
# Keep listening
await asyncio.sleep(30)
-
+
# Unsubscribe
await client.stop_notify("2A37")
```
## Integration with bleak-retry-connector
-[bleak-retry-connector](https://github.com/Bluetooth-Devices/bleak-retry-connector) adds robust retry logic (recommended for production).
+[bleak-retry-connector](https://github.com/Bluetooth-Devices/bleak-retry-connector)
+adds robust retry logic (recommended for production).
-### Installation
+### bleak-retry-connector Installation
```bash
pip install bluetooth-sig bleak-retry-connector
```
-### Example
+### Example (bleak-retry-connector)
```python
import asyncio
@@ -116,7 +121,7 @@ from bluetooth_sig.core import BluetoothSIGTranslator
async def read_with_retry(address: str):
translator = BluetoothSIGTranslator()
-
+
# Establish connection with automatic retries
client = await establish_connection(
BleakClient,
@@ -124,27 +129,28 @@ async def read_with_retry(address: str):
name="Sensor Device",
max_attempts=3
)
-
+
try:
# Read battery level
raw_data = await client.read_gatt_char("2A19")
result = translator.parse_characteristic_data("2A19", raw_data)
- print(f"Battery: {result.value}%")
+ print(f"Battery: {result.value}%")
finally:
await client.disconnect()
```
## Integration with simplepyble
-[simplepyble](https://github.com/OpenBluetoothToolbox/SimpleBLE) is a cross-platform sync BLE library.
+[simplepyble](https://github.com/OpenBluetoothToolbox/SimpleBLE) is a cross-platform
+sync BLE library.
-### Installation
+### simplepyble Installation
```bash
pip install bluetooth-sig simplepyble
```
-### Example
+### Example (simplepyble)
```python
from simplepyble import Adapter, Peripheral
@@ -152,27 +158,27 @@ from bluetooth_sig.core import BluetoothSIGTranslator
def main():
translator = BluetoothSIGTranslator()
-
+
# Get adapter
adapters = Adapter.get_adapters()
if not adapters:
print("No adapters found")
return
-
+
adapter = adapters[0]
-
+
# Scan for devices
adapter.scan_for(5000) # 5 seconds
peripherals = adapter.scan_get_results()
-
+
if not peripherals:
print("No devices found")
return
-
+
# Connect to first device
peripheral = peripherals[0]
peripheral.connect()
-
+
try:
# Find battery service
services = peripheral.services()
@@ -180,7 +186,7 @@ def main():
(s for s in services if s.uuid() == "180F"),
None
)
-
+
if battery_service:
# Find battery level characteristic
battery_char = next(
@@ -188,7 +194,7 @@ def main():
if c.uuid() == "2A19"),
None
)
-
+
if battery_char:
# Read and parse
raw_data = peripheral.read(
@@ -219,10 +225,10 @@ from bluetooth_sig.gatt.exceptions import (
try:
# BLE operation
raw_data = await client.read_gatt_char(uuid)
-
+
# Parse
result = translator.parse_characteristic_data(uuid, raw_data)
-
+
except BleakError as e:
print(f"BLE error: {e}")
except InsufficientDataError as e:
@@ -290,11 +296,11 @@ from bluetooth_sig.gatt.exceptions import BluetoothSIGError
class SensorReader:
"""Read and parse BLE sensor data."""
-
+
def __init__(self, address: str):
self.address = address
self.translator = BluetoothSIGTranslator()
-
+
async def read_battery(self) -> int:
"""Read battery level."""
async with BleakClient(self.address) as client:
@@ -304,7 +310,7 @@ class SensorReader:
raw_data
)
return result.value
-
+
async def read_temperature(self) -> float:
"""Read temperature in °C."""
async with BleakClient(self.address) as client:
@@ -314,18 +320,18 @@ class SensorReader:
raw_data
)
return result.value
-
+
async def read_all(self) -> dict:
"""Read all sensor data."""
results = {}
-
+
async with BleakClient(self.address) as client:
sensors = {
"battery": "2A19",
"temperature": "2A6E",
"humidity": "2A6F",
}
-
+
for name, uuid in sensors.items():
try:
raw_data = await asyncio.wait_for(
@@ -341,20 +347,22 @@ class SensorReader:
print(f"Parse error for {name}: {e}")
except Exception as e:
print(f"BLE error for {name}: {e}")
-
+
return results
async def main():
reader = SensorReader("AA:BB:CC:DD:EE:FF")
-
+
# Read battery
battery = await reader.read_battery()
print(f"Battery: {battery}%")
-
+
# Read all sensors
data = await reader.read_all()
for name, value in data.items():
- print(f"{name}: {value}")
+ print(
+ f"{name}: {value}"
+ )
if __name__ == "__main__":
asyncio.run(main())
@@ -364,4 +372,8 @@ if __name__ == "__main__":
- [Quick Start](../quickstart.md) - Basic usage
- [API Reference](../api/core.md) - Full API documentation
-- [Examples](https://github.com/RonanB96/bluetooth-sig-python/tree/main/examples) - More examples
+- [Examples](https://github.com/RonanB96/bluetooth-sig-python/tree/main/examples)
+ - More examples
+ - Additional resources
+ - Community support
+ - More examples
diff --git a/docs/guides/performance.md b/docs/guides/performance.md
index 876af098..09e6c6b1 100644
--- a/docs/guides/performance.md
+++ b/docs/guides/performance.md
@@ -1,6 +1,7 @@
# Performance Guide
-Tips for optimizing performance when using the Bluetooth SIG Standards Library.
+Tips for optimizing performance when using the Bluetooth SIG Standards
+Library.
## Performance Characteristics
@@ -16,8 +17,8 @@ Tips for optimizing performance when using the Bluetooth SIG Standards Library.
The library is optimized for parsing speed. Typical bottlenecks are:
1. **BLE I/O operations** - Reading from device (milliseconds)
-2. **Network latency** - For remote devices
-3. **Connection management** - Device discovery and pairing
+1. **Network latency** - For remote devices
+1. **Connection management** - Device discovery and pairing
The parsing itself is rarely the bottleneck.
@@ -48,7 +49,7 @@ async with BleakClient(address) as client:
battery_data = await client.read_gatt_char("2A19")
temp_data = await client.read_gatt_char("2A6E")
humidity_data = await client.read_gatt_char("2A6F")
-
+
# Parse offline
battery = translator.parse_characteristic_data("2A19", battery_data)
temp = translator.parse_characteristic_data("2A6E", temp_data)
@@ -103,7 +104,7 @@ from bluetooth_sig.core import BluetoothSIGTranslator
def profile_parsing():
translator = BluetoothSIGTranslator()
data = bytearray([75])
-
+
# Run many iterations
for _ in range(10000):
translator.parse_characteristic_data("2A19", data)
@@ -121,11 +122,13 @@ stats.print_stats(10)
### Registry Caching
-The registry is loaded once and cached. This is automatic and requires no configuration.
+The registry is loaded once and cached. This is automatic and requires
+no configuration.
### Cleanup
-For long-running applications, there's minimal memory accumulation. No special cleanup needed.
+For long-running applications, there's minimal memory accumulation. No special
+cleanup needed.
## Concurrent Operations
@@ -142,14 +145,17 @@ def parse_in_thread(uuid, data):
# Parallel parsing (though rarely needed)
with ThreadPoolExecutor(max_workers=4) as executor:
- futures = [
- executor.submit(parse_in_thread, uuid, data)
- for uuid, data in sensor_data.items()
- ]
- results = [f.result() for f in futures]
+ futures = [
+ executor.submit(parse_in_thread, uuid, data)
+ for uuid, data in sensor_data.items()
+ ]
+ results = [
+ f.result() for f in futures
+ ]
```
-**Note**: Parsing is so fast that parallelization rarely provides benefits. Focus on parallelizing BLE I/O operations instead.
+**Note**: Parsing is so fast that parallelization rarely provides benefits.
+Focus on parallelizing BLE I/O operations instead.
## Real-World Performance
@@ -167,18 +173,21 @@ for _ in range(1000):
elapsed = time.perf_counter() - start
print(f"1000 parses in {elapsed:.3f}s")
-print(f"Average: {elapsed * 1000:.1f}Ξs per parse")
+print(
+ f"Average: {elapsed * 1000:.1f}Ξs per parse"
+)
# Typical output: "1000 parses in 0.050s" (50Ξs avg)
```
-The parsing overhead is negligible compared to BLE operations (typically 10-100ms per read).
+The parsing overhead is negligible compared to BLE operations (typically
+10-100ms per read).
## Recommendations
1. **Focus on BLE optimization** - Connection management, batching
-2. **Reuse translator instances** - Create once, use many times
-3. **Profile your application** - Identify real bottlenecks
-4. **Don't over-optimize** - Parsing is already fast
+1. **Reuse translator instances** - Create once, use many times
+1. **Profile your application** - Identify real bottlenecks
+1. **Don't over-optimize** - Parsing is already fast
## See Also
diff --git a/docs/index.md b/docs/index.md
index e1b7a9f5..ae39a806 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,8 +1,8 @@
# Bluetooth SIG Standards Library
-**A pure Python library for Bluetooth SIG standards interpretation**
+A pure Python library for Bluetooth SIG standards interpretation
-[](https://ronanb96.github.io/bluetooth-sig-python/coverage/)
+[](coverage/)
[](https://www.python.org/downloads/)
[](https://pypi.org/project/bluetooth-sig/)
[](https://opensource.org/licenses/MIT)
@@ -28,11 +28,11 @@ from bluetooth_sig.core import BluetoothSIGTranslator
translator = BluetoothSIGTranslator()
# Resolve UUIDs
-service_info = translator.resolve_uuid("180F") # Battery Service
-print(f"Service: {service_info.name}")
+service_info = translator.resolve_by_uuid("180F") # Battery
+print(f"Service: {service_info.name}") # Service: Battery
# Parse characteristic data
-battery_data = translator.parse_characteristic_data("2A19", bytearray([85]))
+battery_data = translator.parse_characteristic("2A19", bytearray([85]))
print(f"Battery: {battery_data.value}%") # Battery: 85%
```
@@ -40,7 +40,7 @@ print(f"Battery: {battery_data.value}%") # Battery: 85%
-- :material-clock-fast:{ .lg .middle } __Quick Start__
+- :material-clock-fast:{ .lg .middle } __Quick Start__
---
@@ -48,7 +48,7 @@ print(f"Battery: {battery_data.value}%") # Battery: 85%
[:octicons-arrow-right-24: Quick Start](quickstart.md)
-- :material-book-open-variant:{ .lg .middle } __Installation__
+- :material-book-open-variant:{ .lg .middle } __Installation__
---
@@ -56,7 +56,7 @@ print(f"Battery: {battery_data.value}%") # Battery: 85%
[:octicons-arrow-right-24: Installation](installation.md)
-- :material-code-braces:{ .lg .middle } __Usage Guide__
+- :material-code-braces:{ .lg .middle } __Usage Guide__
---
@@ -64,7 +64,7 @@ print(f"Battery: {battery_data.value}%") # Battery: 85%
[:octicons-arrow-right-24: Usage Guide](usage.md)
-- :material-api:{ .lg .middle } __API Reference__
+- :material-api:{ .lg .middle } __API Reference__
---
@@ -76,21 +76,16 @@ print(f"Battery: {battery_data.value}%") # Battery: 85%
## Why Choose This Library?
-Unlike other Bluetooth libraries that focus on device connectivity, this library specializes in **standards interpretation**. It bridges the gap between raw BLE data and meaningful application-level information by:
+Unlike other Bluetooth libraries that focus on device connectivity, this library specializes in **standards interpretation**. It bridges the gap between raw BLE data and meaningful application-level information.
-- **Parsing complex GATT characteristics** according to official specifications
-- **Resolving UUIDs** to human-readable service and characteristic names
-- **Providing type-safe data structures** for all parsed values
-- **Working with any BLE library** for maximum flexibility
-
-[Learn more about what this library solves â](what-it-solves.md)
+[Learn more about what this library solves â](why-use.md)
## Support
- **Issues**: [GitHub Issues](https://github.com/RonanB96/bluetooth-sig-python/issues)
- **Source Code**: [GitHub Repository](https://github.com/RonanB96/bluetooth-sig-python)
- **Documentation**: You're here! ð
-- **Coverage Report**: [Test Coverage](https://ronanb96.github.io/bluetooth-sig-python/coverage/) (Generated from CI)
+- **Coverage Report**: [Test Coverage](coverage/) (Generated from CI)
## License
diff --git a/docs/quickstart.md b/docs/quickstart.md
index 79a769a2..0f88cf6e 100644
--- a/docs/quickstart.md
+++ b/docs/quickstart.md
@@ -2,13 +2,15 @@
Get started with the Bluetooth SIG Standards Library in 5 minutes.
-## Installation
+## Prerequisites
+
+Before using the library, make sure it's installed:
```bash
pip install bluetooth-sig
```
-That's it! The library is ready to use.
+For detailed installation instructions, see the [Installation Guide](installation.md).
## Basic Usage
@@ -24,11 +26,11 @@ translator = BluetoothSIGTranslator()
```python
# Get service information
-service_info = translator.resolve_uuid("180F")
+service_info = translator.resolve_by_uuid("180F")
print(f"Service: {service_info.name}") # Service: Battery Service
# Get characteristic information
-char_info = translator.resolve_uuid("2A19")
+char_info = translator.resolve_by_uuid("2A19")
print(f"Characteristic: {char_info.name}") # Characteristic: Battery Level
```
@@ -36,15 +38,15 @@ print(f"Characteristic: {char_info.name}") # Characteristic: Battery Level
```python
# Parse battery level (0-100%)
-battery_data = translator.parse_characteristic_data("2A19", bytearray([85]))
+battery_data = translator.parse_characteristic("2A19", bytearray([85]))
print(f"Battery: {battery_data.value}%") # Battery: 85%
# Parse temperature (°C)
-temp_data = translator.parse_characteristic_data("2A6E", bytearray([0x64, 0x09]))
+temp_data = translator.parse_characteristic("2A6E", bytearray([0x64, 0x09]))
print(f"Temperature: {temp_data.value}°C") # Temperature: 24.36°C
# Parse humidity (%)
-humidity_data = translator.parse_characteristic_data("2A6F", bytearray([0x3A, 0x13]))
+humidity_data = translator.parse_characteristic("2A6F", bytearray([0x3A, 0x13]))
print(f"Humidity: {humidity_data.value}%") # Humidity: 49.42%
```
@@ -58,38 +60,42 @@ from bluetooth_sig.core import BluetoothSIGTranslator
def main():
# Create translator
translator = BluetoothSIGTranslator()
-
+
# UUID Resolution
print("=== UUID Resolution ===")
- service_info = translator.resolve_uuid("180F")
- print(f"UUID 180F: {service_info.name} ({service_info.type})")
-
+ service_info = translator.resolve_by_uuid("180F")
+ print(f"UUID 180F: {service_info.name}")
+
# Name Resolution
print("\n=== Name Resolution ===")
- battery_level = translator.resolve_name("Battery Level")
+ battery_level = translator.resolve_by_name("Battery Level")
print(f"Battery Level: {battery_level.uuid}")
-
+
# Data Parsing
print("\n=== Data Parsing ===")
-
+
+
# Battery level
- battery_data = translator.parse_characteristic_data("2A19", bytearray([75]))
+ battery_data = translator.parse_characteristic("2A19", bytearray([75]))
print(f"Battery: {battery_data.value}%")
-
+
# Temperature
- temp_data = translator.parse_characteristic_data("2A6E", bytearray([0x64, 0x09]))
+ temp_data = translator.parse_characteristic("2A6E", bytearray([0x64, 0x09]))
print(f"Temperature: {temp_data.value}°C")
-
+
# Humidity
- humidity_data = translator.parse_characteristic_data("2A6F", bytearray([0x3A, 0x13]))
+ humidity_data = translator.parse_characteristic("2A6F", bytearray([0x3A, 0x13]))
print(f"Humidity: {humidity_data.value}%")
-if __name__ == "__main__":
+
+if __name__ == '__main__':
main()
+
```
**Output:**
-```
+
+```text
=== UUID Resolution ===
UUID 180F: Battery Service (service)
@@ -104,103 +110,15 @@ Humidity: 49.42%
## Integration with BLE Libraries
-The library is designed to work with any BLE connection library. Here's how:
-
-### With bleak (Async)
-
-```python
-from bleak import BleakClient
-from bluetooth_sig.core import BluetoothSIGTranslator
-
-async def read_battery_level(address: str):
- translator = BluetoothSIGTranslator()
-
- async with BleakClient(address) as client:
- # Read raw data with bleak
- raw_data = await client.read_gatt_char("2A19")
-
- # Parse with bluetooth-sig
- result = translator.parse_characteristic_data("2A19", raw_data)
- print(f"Battery: {result.value}%")
-```
-
-### With simplepyble (Sync)
-
-```python
-from simplepyble import Peripheral, Adapter
-from bluetooth_sig.core import BluetoothSIGTranslator
-
-def read_battery_level(peripheral: Peripheral):
- translator = BluetoothSIGTranslator()
-
- # Find battery service
- services = peripheral.services()
- battery_service = next(s for s in services if s.uuid() == "180F")
-
- # Find battery level characteristic
- battery_char = next(c for c in battery_service.characteristics()
- if c.uuid() == "2A19")
-
- # Read raw data
- raw_data = peripheral.read(battery_service.uuid(), battery_char.uuid())
-
- # Parse with bluetooth-sig
- result = translator.parse_characteristic_data("2A19", bytearray(raw_data))
- print(f"Battery: {result.value}%")
-```
+The library is designed to work with any BLE connection library. See the [BLE Integration Guide](guides/ble-integration.md) for detailed examples with bleak, simplepyble, and other libraries.
## Common Use Cases
-### Reading Multiple Sensors
-
-```python
-from bluetooth_sig.core import BluetoothSIGTranslator
-
-translator = BluetoothSIGTranslator()
-
-# Simulate reading from multiple sensors
-sensor_data = {
- "2A19": bytearray([85]), # Battery
- "2A6E": bytearray([0x64, 0x09]), # Temperature
- "2A6F": bytearray([0x3A, 0x13]), # Humidity
- "2A6D": bytearray([0x50, 0xC3, 0x00, 0x00]), # Pressure
-}
-
-for uuid, raw_data in sensor_data.items():
- result = translator.parse_characteristic_data(uuid, raw_data)
- print(f"{uuid}: {result.value} {getattr(result, 'unit', '')}")
-```
+For examples of reading multiple sensors and advanced usage patterns, see the [Usage Guide](usage.md).
### Error Handling
-```python
-from bluetooth_sig.core import BluetoothSIGTranslator
-from bluetooth_sig.gatt.exceptions import (
- InsufficientDataError,
- ValueRangeError,
- UUIDResolutionError
-)
-
-translator = BluetoothSIGTranslator()
-
-try:
- # Attempt to parse invalid data
- result = translator.parse_characteristic_data("2A19", bytearray([]))
-except InsufficientDataError as e:
- print(f"Data too short: {e}")
-
-try:
- # Attempt to parse out-of-range value
- result = translator.parse_characteristic_data("2A19", bytearray([150]))
-except ValueRangeError as e:
- print(f"Invalid value: {e}")
-
-try:
- # Attempt to resolve unknown UUID
- info = translator.resolve_uuid("XXXX")
-except UUIDResolutionError as e:
- print(f"Unknown UUID: {e}")
-```
+For comprehensive error handling examples and troubleshooting, see the [Usage Guide](usage.md) and [Testing Guide](testing.md).
## Supported Characteristics
diff --git a/docs/supported-characteristics.md b/docs/supported-characteristics.md
deleted file mode 100644
index 2aaa6474..00000000
--- a/docs/supported-characteristics.md
+++ /dev/null
@@ -1,155 +0,0 @@
-# Supported Characteristics and Services
-
-This page lists all GATT characteristics and services currently supported by the library.
-
-!!! note "Auto-Generated"
- This page is automatically generated from the codebase. The list is updated when new characteristics or services are added.
-
-## Characteristics
-
-The library currently supports **74** GATT characteristics:
-
-
-### Power & Battery
-
-| Characteristic | UUID | Description |
-|----------------|------|-------------|
-| **BatteryLevel** | `N/A` | Battery level characteristic. |
-| **BatteryPowerState** | `N/A` | Battery Level Status characteristic (0x2BED). |
-| **CyclingPowerControlPoint** | `N/A` | Cycling Power Control Point characteristic (0x2A66). |
-| **CyclingPowerFeature** | `N/A` | Cycling Power Feature characteristic (0x2A65). |
-| **CyclingPowerMeasurement** | `N/A` | Cycling Power Measurement characteristic (0x2A63). |
-| **CyclingPowerVector** | `N/A` | Cycling Power Vector characteristic (0x2A64). |
-| **SupportedPowerRange** | `N/A` | Supported Power Range characteristic. |
-| **TxPowerLevel** | `N/A` | Tx Power Level characteristic. |
-
-### Environmental Sensing
-
-| Characteristic | UUID | Description |
-|----------------|------|-------------|
-| **BarometricPressureTrend** | `N/A` | Barometric pressure trend characteristic. |
-| **BloodPressureFeature** | `N/A` | Blood Pressure Feature characteristic (0x2A49). |
-| **BloodPressureMeasurement** | `N/A` | Blood Pressure Measurement characteristic (0x2A35). |
-| **CO2Concentration** | `N/A` | Carbon Dioxide concentration characteristic (0x2B8C). |
-| **Humidity** | `N/A` | Humidity measurement characteristic. |
-| **PM10Concentration** | `N/A` | PM10 particulate matter concentration characteristic (0x2BD7). |
-| **PM1Concentration** | `N/A` | PM1 particulate matter concentration characteristic (0x2BD7). |
-| **PM25Concentration** | `N/A` | PM2.5 particulate matter concentration characteristic (0x2BD6). |
-| **Pressure** | `N/A` | Atmospheric pressure characteristic. |
-| **Temperature** | `N/A` | Temperature measurement characteristic. |
-| **TemperatureMeasurement** | `N/A` | Temperature Measurement characteristic (0x2A1C). |
-| **UVIndex** | `N/A` | UV Index characteristic. |
-
-### Health & Fitness
-
-| Characteristic | UUID | Description |
-|----------------|------|-------------|
-| **BodyCompositionFeature** | `N/A` | Body Composition Feature characteristic (0x2A9B). |
-| **BodyCompositionMeasurement** | `N/A` | Body Composition Measurement characteristic (0x2A9C). |
-| **GlucoseFeature** | `N/A` | Glucose Feature characteristic (0x2A51). |
-| **GlucoseMeasurement** | `N/A` | Glucose Measurement characteristic (0x2A18). |
-| **GlucoseMeasurementContext** | `N/A` | Glucose Measurement Context characteristic (0x2A34). |
-| **HeartRateMeasurement** | `N/A` | Heart Rate Measurement characteristic (0x2A37). |
-| **WeightMeasurement** | `N/A` | Weight Measurement characteristic (0x2A9D). |
-| **WeightScaleFeature** | `N/A` | Weight Scale Feature characteristic (0x2A9E). |
-
-### Sports & Activity
-
-| Characteristic | UUID | Description |
-|----------------|------|-------------|
-| **CSCMeasurement** | `N/A` | CSC (Cycling Speed and Cadence) Measurement characteristic (0x2A5B). |
-| **RSCMeasurement** | `N/A` | RSC (Running Speed and Cadence) Measurement characteristic (0x2A53). |
-
-### Device Information
-
-| Characteristic | UUID | Description |
-|----------------|------|-------------|
-| **FirmwareRevisionString** | `N/A` | Firmware Revision String characteristic. |
-| **HardwareRevisionString** | `N/A` | Hardware Revision String characteristic. |
-| **ManufacturerNameString** | `N/A` | Manufacturer Name String characteristic. |
-| **ModelNumberString** | `N/A` | Model Number String characteristic. |
-| **SerialNumberString** | `N/A` | Serial Number String characteristic. |
-| **SoftwareRevisionString** | `N/A` | Software Revision String characteristic. |
-
-### Electrical
-
-| Characteristic | UUID | Description |
-|----------------|------|-------------|
-| **AverageCurrent** | `N/A` | Average Current characteristic. |
-| **AverageVoltage** | `N/A` | Average Voltage characteristic. |
-| **ElectricCurrent** | `N/A` | Electric Current characteristic. |
-| **ElectricCurrentRange** | `N/A` | Electric Current Range characteristic. |
-| **ElectricCurrentSpecification** | `N/A` | Electric Current Specification characteristic. |
-| **ElectricCurrentStatistics** | `N/A` | Electric Current Statistics characteristic. |
-| **HighVoltage** | `N/A` | High Voltage characteristic. |
-| **Voltage** | `N/A` | Voltage characteristic. |
-| **VoltageFrequency** | `N/A` | Voltage Frequency characteristic. |
-| **VoltageSpecification** | `N/A` | Voltage Specification characteristic. |
-| **VoltageStatistics** | `N/A` | Voltage Statistics characteristic. |
-
-### Other
-
-| Characteristic | UUID | Description |
-|----------------|------|-------------|
-| **AmmoniaConcentration** | `N/A` | Ammonia concentration measurement characteristic (0x2BCF). |
-| **ApparentWindDirection** | `N/A` | Apparent Wind Direction measurement characteristic. |
-| **ApparentWindSpeed** | `N/A` | Apparent Wind Speed measurement characteristic. |
-| **Appearance** | `N/A` | Appearance characteristic. |
-| **DeviceName** | `N/A` | Device Name characteristic. |
-| **DewPoint** | `N/A` | Dew Point measurement characteristic. |
-| **Elevation** | `N/A` | Elevation characteristic. |
-| **HeatIndex** | `N/A` | Heat Index measurement characteristic. |
-| **Illuminance** | `N/A` | Illuminance characteristic (0x2AFB). |
-| **LocalTimeInformation** | `N/A` | Local time information characteristic. |
-| **MagneticDeclination** | `N/A` | Magnetic declination characteristic. |
-| **MagneticFluxDensity2D** | `N/A` | Magnetic flux density 2D characteristic. |
-| **MagneticFluxDensity3D** | `N/A` | Magnetic flux density 3D characteristic. |
-| **MethaneConcentration** | `N/A` | Methane concentration measurement characteristic (0x2BD1). |
-| **NitrogenDioxideConcentration** | `N/A` | Nitrogen dioxide concentration measurement characteristic (0x2BD2). |
-| **Noise** | `N/A` | Noise characteristic (0x2BE4) - Sound pressure level measurement. |
-| **NonMethaneVOCConcentration** | `N/A` | Non-Methane Volatile Organic Compounds concentration characteristic |
-| **OzoneConcentration** | `N/A` | Ozone concentration measurement characteristic (0x2BD4). |
-| **PollenConcentration** | `N/A` | Pollen concentration measurement characteristic (0x2A75). |
-| **PulseOximetryMeasurement** | `N/A` | PLX Continuous Measurement characteristic (0x2A5F). |
-| **Rainfall** | `N/A` | Rainfall characteristic. |
-| **SulfurDioxideConcentration** | `N/A` | Sulfur dioxide concentration measurement characteristic (0x2BD3). |
-| **TimeZone** | `N/A` | Time zone characteristic. |
-| **TrueWindDirection** | `N/A` | True Wind Direction measurement characteristic. |
-| **TrueWindSpeed** | `N/A` | True Wind Speed measurement characteristic. |
-| **VOCConcentration** | `N/A` | Volatile Organic Compounds concentration characteristic (0x2BE7). |
-| **WindChill** | `N/A` | Wind Chill measurement characteristic. |
-
-## Services
-
-The library currently supports **14** GATT services:
-
-| Service | Description |
-|---------|-------------|
-| **AutomationIO** | Automation IO Service implementation. |
-| **Battery** | Battery Service implementation. |
-| **BodyComposition** | Body Composition Service implementation (0x181B). |
-| **CyclingPower** | Cycling Power Service implementation (0x1818). |
-| **CyclingSpeedAndCadence** | Cycling Speed and Cadence Service implementation (0x1816). |
-| **DeviceInformation** | Device Information Service implementation. |
-| **EnvironmentalSensing** | Environmental Sensing Service implementation (0x181A). |
-| **GenericAccess** | Generic Access Service implementation. |
-| **GenericAttribute** | Generic Attribute Service implementation. |
-| **Glucose** | Glucose Service implementation (0x1808). |
-| **HealthThermometer** | Health Thermometer Service implementation (0x1809). |
-| **HeartRate** | Heart Rate Service implementation (0x180D). |
-| **RunningSpeedAndCadence** | Running Speed and Cadence Service implementation (0x1814). |
-| **WeightScale** | Weight Scale Service implementation (0x181D). |
-
-
-## Adding Support for New Characteristics
-
-To add support for a new characteristic:
-
-1. See the [Adding New Characteristics](guides/adding-characteristics.md) guide
-2. Follow the existing patterns in `src/bluetooth_sig/gatt/characteristics/`
-3. Add tests for your new characteristic
-4. Submit a pull request
-
-## Official Bluetooth SIG Registry
-
-This library is based on the official [Bluetooth SIG Assigned Numbers](https://www.bluetooth.com/specifications/assigned-numbers/) registry. The UUID registry is loaded from YAML files in the `bluetooth_sig` submodule.
diff --git a/docs/testing.md b/docs/testing.md
index ed3491f8..7ecb04d6 100644
--- a/docs/testing.md
+++ b/docs/testing.md
@@ -41,30 +41,30 @@ from bluetooth_sig.core import BluetoothSIGTranslator
class TestBLEParsing:
"""Test BLE characteristic parsing without hardware."""
-
+
def test_battery_level_parsing(self):
"""Test battery level parsing with mock data."""
translator = BluetoothSIGTranslator()
-
+
# Mock raw BLE data (no hardware needed)
mock_data = bytearray([75])
-
+
# Parse
result = translator.parse_characteristic_data("2A19", mock_data)
-
+
# Assert
assert result.value == 75
assert 0 <= result.value <= 100
-
+
def test_temperature_parsing(self):
"""Test temperature parsing with mock data."""
translator = BluetoothSIGTranslator()
-
+
# Mock temperature data: 24.36°C
mock_data = bytearray([0x64, 0x09])
-
+
result = translator.parse_characteristic_data("2A6E", mock_data)
-
+
assert result.value == 24.36
assert isinstance(result.value, float)
```
@@ -80,19 +80,19 @@ from bluetooth_sig.gatt.exceptions import (
class TestErrorHandling:
"""Test error handling without hardware."""
-
+
def test_insufficient_data(self):
"""Test error when data is too short."""
translator = BluetoothSIGTranslator()
-
+
# Empty data
with pytest.raises(InsufficientDataError):
translator.parse_characteristic_data("2A19", bytearray([]))
-
+
def test_out_of_range_value(self):
"""Test error when value is out of range."""
translator = BluetoothSIGTranslator()
-
+
# Battery level > 100%
with pytest.raises(ValueRangeError):
translator.parse_characteristic_data("2A19", bytearray([150]))
@@ -122,12 +122,12 @@ async def test_read_battery_with_mock(mock_bleak_client):
"""Test reading battery level with mocked BLE."""
# Setup mock
mock_bleak_client.read_gatt_char.return_value = bytearray([85])
-
+
# Your application code
translator = BluetoothSIGTranslator()
raw_data = await mock_bleak_client.read_gatt_char("2A19")
result = translator.parse_characteristic_data("2A19", raw_data)
-
+
# Assert
assert result.value == 85
mock_bleak_client.read_gatt_char.assert_called_once_with("2A19")
@@ -143,12 +143,12 @@ def test_read_battery_simplepyble_mock():
# Create mock peripheral
mock_peripheral = Mock()
mock_peripheral.read.return_value = bytes([75])
-
+
# Your application code
translator = BluetoothSIGTranslator()
raw_data = mock_peripheral.read("180F", "2A19")
result = translator.parse_characteristic_data("2A19", bytearray(raw_data))
-
+
# Assert
assert result.value == 75
mock_peripheral.read.assert_called_once()
@@ -161,20 +161,20 @@ def test_read_battery_simplepyble_mock():
```python
class TestDataFactory:
"""Factory for creating test data."""
-
+
@staticmethod
def battery_level(percentage: int) -> bytearray:
"""Create battery level test data."""
assert 0 <= percentage <= 100
return bytearray([percentage])
-
+
@staticmethod
def temperature(celsius: float) -> bytearray:
"""Create temperature test data."""
# Temperature encoded as sint16 with 0.01°C resolution
value = int(celsius * 100)
return bytearray(value.to_bytes(2, byteorder='little', signed=True))
-
+
@staticmethod
def humidity(percentage: float) -> bytearray:
"""Create humidity test data."""
@@ -185,12 +185,12 @@ class TestDataFactory:
# Usage
def test_with_factory():
translator = BluetoothSIGTranslator()
-
+
# Generate test data
battery_data = TestDataFactory.battery_level(85)
temp_data = TestDataFactory.temperature(24.36)
humidity_data = TestDataFactory.humidity(49.42)
-
+
# Test parsing
assert translator.parse_characteristic_data("2A19", battery_data).value == 85
assert translator.parse_characteristic_data("2A6E", temp_data).value == 24.36
@@ -266,41 +266,41 @@ Test complete workflows:
```python
class TestIntegration:
"""Integration tests for complete workflows."""
-
+
def test_multiple_characteristics(self):
"""Test parsing multiple characteristics."""
translator = BluetoothSIGTranslator()
-
+
# Simulate reading multiple characteristics
sensor_data = {
"2A19": bytearray([85]), # Battery: 85%
"2A6E": bytearray([0x64, 0x09]), # Temp: 24.36°C
"2A6F": bytearray([0x3A, 0x13]), # Humidity: 49.42%
}
-
+
results = {}
for uuid, data in sensor_data.items():
results[uuid] = translator.parse_characteristic_data(uuid, data)
-
+
# Verify all parsed correctly
assert results["2A19"].value == 85
assert results["2A6E"].value == 24.36
assert results["2A6F"].value == 49.42
-
+
def test_uuid_resolution_workflow(self):
"""Test UUID resolution workflow."""
translator = BluetoothSIGTranslator()
-
+
# Resolve UUID to name
- char_info = translator.resolve_uuid("2A19")
+ char_info = translator.resolve_by_uuid("2A19")
assert char_info.name == "Battery Level"
-
+
# Resolve name to UUID
- battery_uuid = translator.resolve_name("Battery Level")
+ battery_uuid = translator.resolve_by_name("Battery Level")
assert battery_uuid.uuid == "2A19"
-
+
# Round-trip
- assert translator.resolve_uuid(battery_uuid.uuid).name == char_info.name
+ assert translator.resolve_by_name(battery_uuid.uuid).name == char_info.name
```
## Performance Testing
@@ -312,18 +312,18 @@ def test_parsing_performance():
"""Test parsing performance."""
translator = BluetoothSIGTranslator()
data = bytearray([75])
-
+
# Warm up
for _ in range(100):
translator.parse_characteristic_data("2A19", data)
-
+
# Measure
start = time.perf_counter()
iterations = 10000
for _ in range(iterations):
translator.parse_characteristic_data("2A19", data)
elapsed = time.perf_counter() - start
-
+
# Should be fast (< 100Ξs per parse)
avg_time = elapsed / iterations
assert avg_time < 0.0001, f"Parsing too slow: {avg_time:.6f}s per iteration"
@@ -334,7 +334,7 @@ def test_parsing_performance():
Recommended test structure:
-```
+```text
tests/
âââ conftest.py # Shared fixtures
âââ test_core/
@@ -367,25 +367,25 @@ jobs:
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12"]
-
+
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
-
+
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
-
+
- name: Install dependencies
run: |
pip install -e ".[dev,test]"
-
+
- name: Run tests
run: |
pytest tests/ --cov=src/bluetooth_sig --cov-report=xml
-
+
- name: Upload coverage
uses: codecov/codecov-action@v3
```
@@ -432,10 +432,10 @@ def test_temperature_parsing():
# Arrange
translator = BluetoothSIGTranslator()
data = bytearray([0x64, 0x09])
-
+
# Act
result = translator.parse_characteristic_data("2A6E", data)
-
+
# Assert
assert result.value == 24.36
```
diff --git a/docs/usage.md b/docs/usage.md
index e2a3e6e3..1bbd61f4 100644
--- a/docs/usage.md
+++ b/docs/usage.md
@@ -9,8 +9,8 @@ from bluetooth_sig.core import BluetoothSIGTranslator
translator = BluetoothSIGTranslator()
# Resolve UUIDs to get information
-service_info = translator.resolve_uuid("180F") # Battery Service
-char_info = translator.resolve_uuid("2A19") # Battery Level
+service_info = translator.resolve_by_uuid("180F") # Battery Service
+char_info = translator.resolve_by_uuid("2A19") # Battery Level
print(f"Service: {service_info.name}")
print(f"Characteristic: {char_info.name}")
@@ -25,21 +25,35 @@ def main():
translator = BluetoothSIGTranslator()
# UUID resolution
- uuid_info = translator.resolve_uuid("180F")
+ uuid_info = translator.resolve_by_uuid("180F")
print(f"UUID 180F: {uuid_info.name}")
# Name resolution
- name_info = translator.resolve_name("Battery Level")
+ name_info = translator.resolve_by_name("Battery Level")
print(f"Battery Level UUID: {name_info.uuid}")
# Data parsing
- parsed = translator.parse_characteristic_data("2A19", bytearray([85]))
+ parsed = translator.parse_characteristic("2A19", bytearray([85]))
print(f"Battery level: {parsed.value}%")
+
if __name__ == "__main__":
main()
```
+For more basic usage examples, see the [Quick Start Guide](quickstart.md).
+
+______________________________________________________________________
+
+## Troubleshooting
+
+If you encounter errors when parsing characteristic data (e.g., unknown UUID, insufficient data, or value out of range), check:
+
+- The UUID and data format match the official specification
+- Your data is a bytearray of the correct length
+
+See the [Testing Guide](testing.md) for more on validating your setup and troubleshooting parsing issues.
+
## Device Class
The `Device` class provides a high-level abstraction for grouping BLE device services, characteristics, encryption requirements, and advertiser data. It serves as a pure SIG standards translator, not a BLE connection manager.
diff --git a/docs/what-it-does-not-solve.md b/docs/what-it-does-not-solve.md
index 239689f4..8836c2d3 100644
--- a/docs/what-it-does-not-solve.md
+++ b/docs/what-it-does-not-solve.md
@@ -4,7 +4,7 @@ Understanding what this library **does not** do is just as important as understa
## â BLE Device Connection & Communication
-### What This Library Does NOT Do
+### What This Library Does NOT Do (BLE Connection)
This library **does not** handle:
@@ -37,7 +37,7 @@ from bluetooth_sig.core import BluetoothSIGTranslator
async with BleakClient(device_address) as client:
# bleak reads the raw data
raw_data = await client.read_gatt_char("2A19")
-
+
# bluetooth-sig interprets the data
translator = BluetoothSIGTranslator()
result = translator.parse_characteristic_data("2A19", raw_data)
@@ -45,29 +45,31 @@ async with BleakClient(device_address) as client:
```
**Separation of Concerns:**
+
- **BLE Library** â Device discovery, connection, I/O
- **bluetooth-sig** â Standards interpretation, data parsing
----
+______________________________________________________________________
## â Bluetooth Classic Support
-### What This Library Does NOT Do
+### What This Library Does NOT Do (Bluetooth Classic)
This library **only** supports Bluetooth Low Energy (BLE) / GATT characteristics.
**Not Supported:**
+
- Bluetooth Classic (BR/EDR)
- RFCOMM profiles
- A2DP (audio streaming)
- HFP (hands-free profile)
- Other classic Bluetooth profiles
-### Reason
+### Reason (Bluetooth Classic)
Bluetooth Classic and BLE are fundamentally different protocols with different standards. This library focuses exclusively on BLE/GATT standards as defined by Bluetooth SIG.
----
+______________________________________________________________________
## â
Custom Characteristics ARE Supported
@@ -76,6 +78,7 @@ Bluetooth Classic and BLE are fundamentally different protocols with different s
While the library provides **70+ official Bluetooth SIG standard characteristics**, it also **fully supports adding custom characteristics**.
**You CAN:**
+
- â
Create vendor-specific characteristics
- â
Add custom protocols on top of BLE
- â
Implement proprietary data formats
@@ -92,12 +95,12 @@ from bluetooth_sig.types.uuid import BluetoothUUID
class MyCustomCharacteristic(BaseCharacteristic):
"""Your custom characteristic."""
-
+
_info = CharacteristicInfo(
uuid=BluetoothUUID("ABCD"), # Your UUID
name="My Custom Characteristic"
)
-
+
def decode_value(self, data: bytearray) -> int:
"""Your parsing logic."""
return int(data[0])
@@ -107,17 +110,17 @@ custom_char = MyCustomCharacteristic()
value = custom_char.decode_value(bytearray([42]))
```
-**See the [Adding New Characteristics Guide](../guides/adding-characteristics/) for complete examples.**
+**See the [Adding New Characteristics Guide](guides/adding-characteristics.md) for complete examples.**
### What Is NOT Included Out-of-the-Box
The library includes 70+ official SIG characteristics, but doesn't include every possible vendor-specific characteristic. You need to implement those yourself using the extension API.
----
+______________________________________________________________________
## â Real-Time Streaming & High-Frequency Data
-### What This Library Does NOT Do
+### What This Library Does NOT Do (Real-Time Streaming)
This library is optimized for **parsing individual characteristic reads**, not:
@@ -130,12 +133,14 @@ This library is optimized for **parsing individual characteristic reads**, not:
### Use Cases Where This Matters
**Not Ideal For:**
+
- Audio streaming (use A2DP or dedicated audio libraries)
- High-frequency sensor data (>100 Hz)
- Video transmission
- Large file transfers
**Perfect For:**
+
- Periodic sensor readings (temperature, humidity, battery)
- On-demand characteristic reads
- Notification parsing (heart rate, step count)
@@ -143,28 +148,30 @@ This library is optimized for **parsing individual characteristic reads**, not:
### Performance Characteristics
-- **Typical parsing time:** <1ms per characteristic
+- **Typical parsing time:** \<1ms per characteristic
- **Memory footprint:** Minimal (no buffering)
- **Throughput:** Optimized for individual reads, not streaming
----
+______________________________________________________________________
## â Firmware or Embedded Device Implementation
-### What This Library Does NOT Do
+### What This Library Does NOT Do (Firmware/Embedded)
This is a **client-side** library for applications that interact with BLE devices.
**Not Designed For:**
+
- Running on BLE peripheral devices
- Embedded systems (ESP32, Arduino, nRF52, etc.)
- Firmware implementation
- BLE server/peripheral role
- Resource-constrained environments
-### Reason
+### Reason (Embedded/Firmware)
This library:
+
- Requires Python 3.9+ runtime
- Uses standard library features not available in embedded contexts
- Focuses on parsing from a client perspective
@@ -173,17 +180,19 @@ This library:
### Alternative for Embedded
For embedded/firmware development, use:
+
- Platform-specific BLE stacks (Nordic SDK, ESP-IDF, etc.)
- Embedded C/C++ BLE libraries
- Platform vendor SDKs
----
+______________________________________________________________________
## â Device Management & State Tracking
-### What This Library Does NOT Do
+### What This Library Does NOT Do (Device Management)
**Not Included:**
+
- Device state management
- Connection history tracking
- Device pairing storage
@@ -196,8 +205,8 @@ For embedded/firmware development, use:
These features are typically provided by:
1. **BLE libraries** (bleak-retry-connector provides retry logic)
-2. **Your application** (track device state as needed)
-3. **Platform services** (OS-level Bluetooth management)
+1. **Your application** (track device state as needed)
+1. **Platform services** (OS-level Bluetooth management)
```python
# This library doesn't maintain device state
@@ -209,15 +218,16 @@ result2 = translator.parse_characteristic_data("2A19", data2)
# No state maintained between calls
```
----
+______________________________________________________________________
## â GUI or User Interface
-### What This Library Does NOT Do
+### What This Library Does NOT Do (GUI/Interface)
This is a **library**, not an application.
**Not Included:**
+
- Desktop applications
- Mobile apps
- Web interfaces
@@ -245,13 +255,14 @@ def parse_data(uuid):
return jsonify({"value": result.value})
```
----
+______________________________________________________________________
## â Protocol Implementation
-### What This Library Does NOT Do
+### What This Library Does NOT Do (Protocol Implementation)
**Not Provided:**
+
- BLE stack implementation
- GATT server implementation
- ATT protocol handling
@@ -263,35 +274,38 @@ def parse_data(uuid):
This library works at the **application layer**, interpreting data according to GATT profile specifications. Lower-level protocol details are handled by your BLE library and operating system.
----
+______________________________________________________________________
## â Hardware Abstraction
-### What This Library Does NOT Do
+### What This Library Does NOT Do (Hardware Abstraction)
**No Hardware Dependencies:**
+
- Bluetooth adapter management
- Hardware initialization
- Driver installation
- Platform-specific configuration
- USB dongle management
-### Reason
+### Reason (Hardware Abstraction)
Hardware abstraction is provided by:
+
1. **Operating system** Bluetooth stack
-2. **BLE library** (bleak, simplepyble, etc.)
-3. **Platform drivers**
+1. **BLE library** (bleak, simplepyble, etc.)
+1. **Platform drivers**
This library remains hardware-agnostic by working with already-connected data.
----
+______________________________________________________________________
## â Testing Infrastructure for BLE Devices
-### What This Library Does NOT Do
+### What This Library Does NOT Do (Testing Infrastructure)
**Not Included:**
+
- BLE device simulators
- Mock BLE peripherals
- Hardware test fixtures
@@ -308,15 +322,15 @@ from bluetooth_sig.core import BluetoothSIGTranslator
def test_battery_parsing():
translator = BluetoothSIGTranslator()
-
+
# Mock raw data (no real BLE device needed)
mock_battery_data = bytearray([85])
-
+
result = translator.parse_characteristic_data("2A19", mock_battery_data)
assert result.value == 85
```
----
+______________________________________________________________________
## Clear Boundaries: What's In Scope vs Out of Scope
@@ -340,7 +354,7 @@ def test_battery_parsing():
- GUI/application layer
- Hardware abstraction
----
+______________________________________________________________________
## Architecture Decision
@@ -349,28 +363,29 @@ This focused scope is **intentional design**:
### Benefits
1. **Simplicity** - One job, done well
-2. **Flexibility** - Works with any BLE library
-3. **Maintainability** - Focused on standards, not connections
-4. **Testability** - Easy to test without hardware
-5. **Portability** - Platform-agnostic
+1. **Flexibility** - Works with any BLE library
+1. **Maintainability** - Focused on standards, not connections
+1. **Testability** - Easy to test without hardware
+1. **Portability** - Platform-agnostic
### Philosophy
> "Do one thing and do it well" - Unix Philosophy
By focusing exclusively on **standards interpretation**, this library remains:
+
- Simple to understand
- Easy to maintain
- Compatible with any BLE stack
- Testable without hardware
----
+______________________________________________________________________
## Recommended Tool Stack
For a complete BLE solution:
-```
+```text
âââââââââââââââââââââââââââââââââââââââââââââââ
â Your Application â
â (GUI, business logic, state management) â
@@ -394,17 +409,19 @@ For a complete BLE solution:
Each layer handles its specific responsibilities.
----
+______________________________________________________________________
## Summary
**This library is:**
+
- A standards interpretation library
- For parsing GATT characteristics
- Framework-agnostic
- Focused on data translation
**This library is NOT:**
+
- A BLE connection manager
- A device management system
- An application framework
diff --git a/docs/what-it-solves.md b/docs/what-it-solves.md
index 52f61177..558b30a2 100644
--- a/docs/what-it-solves.md
+++ b/docs/what-it-solves.md
@@ -4,7 +4,7 @@ This library addresses specific pain points when working with Bluetooth Low Ener
## Problem 1: Standards Interpretation Complexity
-### The Challenge
+### The Challenge (Standards Interpretation)
Bluetooth SIG specifications are detailed technical documents that define how to encode/decode data for each characteristic. Implementing these correctly requires:
@@ -17,6 +17,7 @@ Bluetooth SIG specifications are detailed technical documents that define how to
### Example: Temperature Characteristic (0x2A6E)
**Specification Requirements:**
+
- 2 bytes (sint16)
- Little-endian byte order
- Resolution: 0.01°C
@@ -24,23 +25,25 @@ Bluetooth SIG specifications are detailed technical documents that define how to
- Valid range: -273.15°C to +327.67°C
**Manual Implementation:**
+
```python
def parse_temperature(data: bytes) -> float | None:
if len(data) != 2:
raise ValueError("Temperature requires 2 bytes")
-
+
raw_value = int.from_bytes(data, byteorder='little', signed=True)
-
+
if raw_value == -32768: # 0x8000
return None # Not available
-
+
if raw_value < -27315 or raw_value > 32767:
raise ValueError("Temperature out of range")
-
+
return raw_value * 0.01
```
**With bluetooth-sig:**
+
```python
from bluetooth_sig.core import BluetoothSIGTranslator
@@ -49,7 +52,7 @@ result = translator.parse_characteristic_data("2A6E", data)
# Handles all validation, conversion, and edge cases automatically
```
-### â
What We Solve
+### â
What We Solve (Standards Interpretation)
- **Automatic standards compliance** - All 70+ characteristics follow official specs
- **Unit conversion handling** - Correct scaling factors applied automatically
@@ -57,11 +60,11 @@ result = translator.parse_characteristic_data("2A6E", data)
- **Validation** - Input data validated before parsing
- **Type safety** - Structured data returned, not raw bytes
----
+______________________________________________________________________
## Problem 2: UUID Management & Resolution
-### The Challenge
+### The Challenge (UUID Management)
Bluetooth uses UUIDs to identify services and characteristics:
@@ -71,9 +74,9 @@ Bluetooth uses UUIDs to identify services and characteristics:
Both represent "Battery Service", but you need to:
1. Maintain a mapping of UUIDs to names
-2. Handle both short and long forms
-3. Support reverse lookup (name â UUID)
-4. Keep up with Bluetooth SIG registry updates
+1. Handle both short and long forms
+1. Support reverse lookup (name â UUID)
+1. Keep up with Bluetooth SIG registry updates
### Manual Approach
@@ -94,7 +97,7 @@ CHARACTERISTIC_UUIDS = {
}
# Handling lookups
-def resolve_uuid(uuid: str) -> str:
+def resolve_by_name(uuid: str) -> str:
# Short form?
if len(uuid) == 4:
return SERVICE_UUIDS.get(uuid) or CHARACTERISTIC_UUIDS.get(uuid)
@@ -105,7 +108,7 @@ def resolve_uuid(uuid: str) -> str:
return "Unknown"
```
-### â
What We Solve
+### â
What We Solve (UUID Management)
```python
from bluetooth_sig.core import BluetoothSIGTranslator
@@ -113,11 +116,11 @@ from bluetooth_sig.core import BluetoothSIGTranslator
translator = BluetoothSIGTranslator()
# Automatic UUID resolution (short or long form)
-info = translator.resolve_uuid("180F")
-info = translator.resolve_uuid("0000180f-0000-1000-8000-00805f9b34fb") # Same result
+info = translator.resolve_by_uuid("180F")
+info = translator.resolve_by_uuid("0000180f-0000-1000-8000-00805f9b34fb") # Same result
# Reverse lookup
-battery_service = translator.resolve_name("Battery Service")
+battery_service = translator.resolve_by_name("Battery Service")
print(battery_service.uuid) # "180F"
# Get full information
@@ -131,11 +134,11 @@ print(info.uuid) # "180F"
- **Both directions** - UUID â name and name â UUID
- **Multiple formats** - Handles short and long UUID forms
----
+______________________________________________________________________
## Problem 3: Type Safety & Data Validation
-### The Challenge
+### The Challenge (Type Safety)
Raw BLE data is just bytes. Without proper typing:
@@ -156,7 +159,7 @@ result = parse_battery(some_data)
# No type hints, no validation, no structure
```
-### â
What We Solve
+### â
What We Solve (Type Safety)
```python
from bluetooth_sig.core import BluetoothSIGTranslator
@@ -174,7 +177,7 @@ print(result.unit) # "%"
temp_result = translator.parse_characteristic_data("2A1C", data)
# Returns TemperatureMeasurement dataclass with:
# - value: float
-# - unit: str
+# - unit: str
# - timestamp: datetime | None
# - temperature_type: str | None
```
@@ -184,11 +187,11 @@ temp_result = translator.parse_characteristic_data("2A1C", data)
- **IDE support** - Autocomplete and inline documentation
- **Type checking** - Works with mypy, pyright, etc.
----
+______________________________________________________________________
## Problem 4: Framework Lock-in
-### The Challenge
+### The Challenge (Framework Lock-in)
Many BLE libraries combine connection management with data parsing, forcing you to:
@@ -197,7 +200,7 @@ Many BLE libraries combine connection management with data parsing, forcing you
- Be limited to their supported platforms
- Migrate everything if you want to change BLE libraries
-### â
What We Solve
+### â
What We Solve (Framework Lock-in)
**Framework-agnostic design** - Parse data from any BLE library:
@@ -228,11 +231,11 @@ result = translator.parse_characteristic_data(uuid, data)
- **Platform flexibility** - Not tied to specific OS/platform
- **Testing** - Easy to mock BLE interactions
----
+______________________________________________________________________
## Problem 5: Maintenance Burden
-### The Challenge
+### The Challenge (Maintenance Burden)
Maintaining a custom BLE parsing implementation requires:
@@ -242,7 +245,7 @@ Maintaining a custom BLE parsing implementation requires:
- Keeping up with new data formats
- Ensuring backwards compatibility
-### â
What We Solve
+### â
What We Solve (Maintenance Burden)
- **Centralized maintenance** - One library, many users
- **SIG registry updates** - New characteristics added as standards evolve
@@ -250,16 +253,17 @@ Maintaining a custom BLE parsing implementation requires:
- **Specification compliance** - Validated against official specs
- **Version management** - Clear versioning and changelog
----
+______________________________________________________________________
## Problem 6: Complex Multi-Field Characteristics
-### The Challenge
+### The Challenge (Multi-Field Characteristics)
Many characteristics have conditional fields based on flags:
**Temperature Measurement (0x2A1C):**
-```
+
+```text
Byte 0: Flags
- Bit 0: Temperature unit (0=°C, 1=°F)
- Bit 1: Timestamp present
@@ -275,22 +279,22 @@ Byte 12: Temperature Type (if bit 2 set)
def parse_temp_measurement(data: bytes) -> dict:
flags = data[0]
offset = 1
-
+
# Parse temperature (IEEE-11073 SFLOAT - complex format)
temp_bytes = data[offset:offset+4]
temp_value = parse_ieee_sfloat(temp_bytes) # Another complex function
offset += 4
-
+
# Conditional fields
timestamp = None
if flags & 0x02:
timestamp = parse_timestamp(data[offset:offset+7])
offset += 7
-
+
temp_type = None
if flags & 0x04:
temp_type = data[offset]
-
+
return {
"value": temp_value,
"unit": "°F" if flags & 0x01 else "°C",
@@ -299,7 +303,7 @@ def parse_temp_measurement(data: bytes) -> dict:
}
```
-### â
What We Solve
+### â
What We Solve (Multi-Field Characteristics)
```python
from bluetooth_sig.core import BluetoothSIGTranslator
@@ -312,7 +316,7 @@ result = translator.parse_characteristic_data("2A1C", data)
# Returns type-safe structured data
```
----
+______________________________________________________________________
## Summary: Key Problems Solved
diff --git a/docs/why-use.md b/docs/why-use.md
index af435b8f..4f87084f 100644
--- a/docs/why-use.md
+++ b/docs/why-use.md
@@ -44,7 +44,7 @@ from bluetooth_sig.core import BluetoothSIGTranslator
translator = BluetoothSIGTranslator()
# Parse according to official specifications
-temp_data = translator.parse_characteristic_data("2A6E", bytearray([0x64, 0x09]))
+temp_data = translator.parse_characteristic("2A6E", bytearray([0x64, 0x09]))
print(f"Temperature: {temp_data.value}°C") # Temperature: 24.36°C
```
@@ -52,11 +52,11 @@ print(f"Temperature: {temp_data.value}°C") # Temperature: 24.36°C
```python
# Resolve UUIDs to names
-service_info = translator.resolve_uuid("180F")
+service_info = translator.resolve_by_uuid("180F")
print(service_info.name) # "Battery Service"
# Reverse lookup
-battery_service = translator.resolve_name("Battery Service")
+battery_service = translator.resolve_by_name("Battery Service")
print(battery_service.uuid) # "180F"
```
@@ -64,7 +64,7 @@ print(battery_service.uuid) # "180F"
```python
# Get structured data, not raw bytes
-battery_data = translator.parse_characteristic_data("2A19", bytearray([85]))
+battery_data = translator.parse_characteristic("2A19", bytearray([85]))
# battery_data is a typed dataclass with validation
assert battery_data.value == 85
@@ -73,19 +73,19 @@ assert 0 <= battery_data.value <= 100 # Automatically validated
## When Should You Use This Library?
-### â
Perfect For:
+### â
Perfect For
- **Application Developers**: Building apps that need to display BLE sensor data
- **IoT Projects**: Reading data from Bluetooth sensors and devices
- **Testing & Validation**: Verifying BLE device implementations
- **Protocol Implementation**: Building BLE client applications
-- **Research & Analysis**: Analyzing BLE device behavior
+- **Research & Analysis**: Analysing BLE device behaviour
+- **Custom Protocols**: Supports custom GATT characteristics via extension API
-### â Not Designed For:
+### â Not Designed For
- **BLE Connection Management**: Use `bleak`, `simplepyble`, or similar libraries for actual device connections
- **Firmware Development**: This is a client-side library, not for embedded devices
-- **Custom Protocols**: Only supports official Bluetooth SIG standards
- **Real-time Streaming**: Optimized for parsing, not high-frequency streaming
## Key Differentiators
@@ -102,12 +102,12 @@ Works with **any** BLE connection library:
# Works with bleak
from bleak import BleakClient
raw_data = await client.read_gatt_char(uuid)
-parsed = translator.parse_characteristic_data(uuid, raw_data)
+parsed = translator.parse_characteristic(uuid, raw_data)
# Works with simplepyble
from simplepyble import Peripheral
raw_data = peripheral.read(service_uuid, char_uuid)
-parsed = translator.parse_characteristic_data(char_uuid, raw_data)
+parsed = translator.parse_characteristic(char_uuid, raw_data)
# Works with ANY BLE library
```
@@ -151,7 +151,7 @@ Support for 70+ characteristics across multiple service categories:
## Real-World Example
-### Without bluetooth-sig:
+### Without bluetooth-sig
```python
# Manual parsing (error-prone)
@@ -171,7 +171,7 @@ UUID_MAP = {
}
```
-### With bluetooth-sig:
+### With bluetooth-sig
```python
from bluetooth_sig.core import BluetoothSIGTranslator
@@ -179,7 +179,7 @@ from bluetooth_sig.core import BluetoothSIGTranslator
translator = BluetoothSIGTranslator()
# One line, standards-compliant, type-safe
-result = translator.parse_characteristic_data("2A19", data)
+result = translator.parse_characteristic("2A19", data)
```
## Next Steps
diff --git a/docs_hooks.py b/docs_hooks.py
new file mode 100644
index 00000000..04532608
--- /dev/null
+++ b/docs_hooks.py
@@ -0,0 +1,27 @@
+# type: ignore
+"""MkDocs hooks to automatically generate characteristics documentation before building."""
+
+import subprocess
+import sys
+from pathlib import Path
+
+
+def on_pre_build(config, **kwargs):
+ """Run the generate script before building documentation."""
+ script_path = Path(__file__).parent / "scripts" / "generate_char_service_list.py"
+
+ if not script_path.exists():
+ print(f"Warning: Generate script not found at {script_path}")
+ return
+
+ try:
+ print("Running characteristics generation script...")
+ subprocess.run(
+ [sys.executable, str(script_path)], cwd=Path(__file__).parent, capture_output=True, text=True, check=True
+ )
+ print("â Characteristics documentation generated successfully")
+ except subprocess.CalledProcessError as e:
+ print(f"Error: Failed to generate characteristics: {e}")
+ print(f"stdout: {e.stdout}")
+ print(f"stderr: {e.stderr}")
+ raise
diff --git a/examples/README.md b/examples/README.md
index 29c4a8ae..f580162d 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -5,6 +5,7 @@ This directory contains clean, focused examples demonstrating the core functiona
## Example BLE Libraries
### with_bleak_retry.py
+
Demonstrates robust BLE connections using Bleak with retry logic and SIG parsing.
```bash
@@ -13,6 +14,7 @@ python examples/with_bleak_retry.py --scan
```
### with_simpleble.py
+
Shows integration with SimplePyBLE (cross-platform synchronous BLE library) and SIG parsing.
```bash
@@ -23,6 +25,7 @@ python examples/with_simpleble.py --scan
## Core Examples
### basic_usage.py
+
Demonstrates basic read/write operations with the bluetooth_sig library.
```bash
@@ -30,6 +33,7 @@ python examples/basic_usage.py --address 12:34:56:78:9A:BC
```
### service_discovery.py
+
Shows the Device class API for service and characteristic discovery.
```bash
@@ -37,6 +41,7 @@ python examples/service_discovery.py --address 12:34:56:78:9A:BC
```
### notifications.py
+
Handles BLE notifications with characteristic parsing.
```bash
@@ -44,6 +49,7 @@ python examples/notifications.py --address 12:34:56:78:9A:BC --characteristic 2A
```
### advertising_parsing.py
+
Parses BLE advertising data packets using the AdvertisingParser.
```bash
@@ -51,6 +57,7 @@ python examples/advertising_parsing.py --data "02010605FF4C001005011C7261F4"
```
### pure_sig_parsing.py
+
Shows pure SIG standards parsing without any BLE connection library dependencies.
```bash
@@ -60,6 +67,7 @@ python examples/pure_sig_parsing.py
## Benchmarks
### benchmarks/parsing_performance.py
+
Comprehensive performance benchmark for parsing operations. Measures parse latency, compares manual vs library parsing, and provides optimization recommendations.
```bash
@@ -74,6 +82,7 @@ python examples/benchmarks/parsing_performance.py --quick
```
**Output includes:**
+
- Single characteristic parsing performance
- Batch parsing vs individual parsing comparison
- UUID resolution performance
@@ -129,7 +138,7 @@ The examples will automatically use available BLE libraries and handle library a
This examples directory follows these principles:
1. **Minimal Overlap** - Each example focuses on a specific use case
-2. **Clean Separation** - Utilities are organized by functionality in the `utils/` package
-3. **Library Agnostic** - Core SIG parsing works with any BLE library
-4. **Production Ready** - Examples demonstrate robust patterns suitable for production use
-5. **Performance Aware** - Benchmarks and profiling tools help optimize real-world usage
+1. **Clean Separation** - Utilities are organized by functionality in the `utils/` package
+1. **Library Agnostic** - Core SIG parsing works with any BLE library
+1. **Production Ready** - Examples demonstrate robust patterns suitable for production use
+1. **Performance Aware** - Benchmarks and profiling tools help optimize real-world usage
diff --git a/examples/benchmarks/parsing_performance.py b/examples/benchmarks/parsing_performance.py
index 79456954..36a18d10 100755
--- a/examples/benchmarks/parsing_performance.py
+++ b/examples/benchmarks/parsing_performance.py
@@ -180,7 +180,7 @@ def benchmark_uuid_resolution(session: ProfilingSession) -> None:
# Name resolution
name_resolution = benchmark_function(
- lambda: translator.resolve_uuid("Battery Level"),
+ lambda: translator.resolve_by_name("Battery Level"),
iterations=iterations,
operation="Name resolution",
)
diff --git a/mkdocs.yml b/mkdocs.yml
index 0f1c8300..c19a4968 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -30,10 +30,14 @@ theme:
- navigation.expand
- navigation.top
- navigation.tracking
+ - navigation.indexes
- search.suggest
- search.highlight
+ - search.share
- content.code.copy
- content.code.annotate
+ - content.tooltips
+ - content.tabs.link
plugins:
- search
@@ -47,6 +51,13 @@ plugins:
show_root_heading: true
show_root_toc_entry: false
heading_level: 2
+ inherited_members: true
+ show_labels: true
+ show_symbol_type_heading: true
+ show_symbol_type_toc: true
+
+hooks:
+ - docs_hooks.py
markdown_extensions:
- pymdownx.highlight:
@@ -67,47 +78,59 @@ markdown_extensions:
- md_in_html
- toc:
permalink: true
+ - pymdownx.arithmatex:
+ generic: true
+ - pymdownx.betterem:
+ smart_enable: all
+ - pymdownx.caret
+ - pymdownx.mark
+ - pymdownx.tilde
+ - pymdownx.tasklist:
+ custom_checkbox: true
+ - pymdownx.magiclink:
+ normalize_issue_symbols: true
+ repo_url_shorthand: true
+ user: RonanB96
+ repo: bluetooth-sig-python
+ - pymdownx.smartsymbols
+ - meta
not_in_nav: |
- README.md
- AGENT_GUIDE.md
- BLUETOOTH_SIG_ARCHITECTURE.md
- PERFORMANCE.md
+ coverage/**
nav:
- Home: index.md
- - Getting Started:
+ - Tutorials:
- Installation: installation.md
- Quick Start: quickstart.md
- - Usage Guide: usage.md
- - Core Concepts:
- - Why Use This Library: why-use.md
- - What Problems It Solves: what-it-solves.md
- - What It Does NOT Solve: what-it-does-not-solve.md
- - Architecture Overview: architecture.md
- - Guides:
+ - How-to guides:
+ - Using the Library: usage.md
- BLE Integration: guides/ble-integration.md
- Adding New Characteristics: guides/adding-characteristics.md
- Performance Optimization: guides/performance.md
- - API Reference:
+ - Contributing: contributing.md
+ - Testing: testing.md
+ - Reference:
- Core API: api/core.md
- GATT Layer: api/gatt.md
- Registry System: api/registry.md
- Types & Enums: api/types.md
- Supported Characteristics: supported-characteristics.md
- - Development:
- - Contributing: contributing.md
- - Testing: testing.md
+ - Explanation:
+ - Why Use This Library: why-use.md
+ - What Problems It Solves: what-it-solves.md
+ - What It Does NOT Solve: what-it-does-not-solve.md
+ - Architecture Overview: architecture.md
+ - Community:
- Code of Conduct: code-of-conduct.md
+ - GitHub README: github-readme.md
extra:
social:
- icon: fontawesome/brands/github
link: https://github.com/RonanB96/bluetooth-sig-python
- version:
- provider: mike
-copyright: Copyright © 2024 RonanB96
+copyright: Copyright © 2025 RonanB96
# Coverage report integration - served at /coverage/
# Generated by GitHub Actions from pytest-cov
diff --git a/pyproject.toml b/pyproject.toml
index 311cf6ff..f6cdfea1 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -29,6 +29,7 @@ classifiers = [
dependencies = [
"pyyaml~=6.0.0",
"msgspec>=0.18.0",
+ "typing_extensions>=4.0.0",
]
[project.urls]
@@ -43,8 +44,8 @@ dev = [
"pytest-cov>=6.2,<8",
"pylint~=3.3",
"ruff~=0.13",
- "mypy~=1.0",
"types-PyYAML~=6.0",
+ "mypy~=1.0",
"ipdb~=0.13",
"coverage~=7.0",
]
@@ -52,6 +53,7 @@ test = [
"pytest==8.4.2",
"pytest-asyncio==1.2.0",
"pytest-cov>=6.2,<8",
+ "pytest-xdist>=3.0.0",
"bleak>=0.21.0",
"bleak-retry-connector>=2.13.1,<3",
"simplepyble>=0.10.3",
@@ -147,6 +149,7 @@ ignore = [
[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"] # Ignore unused imports in __init__.py files
+"docs_hooks.py" = ["ANN001", "ANN002", "ANN003", "ANN201"] # MkDocs hooks must match their interface exactly
[tool.ruff.format]
# Use black-compatible formatting
diff --git a/scripts/generate_char_service_list.py b/scripts/generate_char_service_list.py
new file mode 100755
index 00000000..98b76dcc
--- /dev/null
+++ b/scripts/generate_char_service_list.py
@@ -0,0 +1,276 @@
+#!/usr/bin/env python3
+"""Generate a markdown file listing all supported characteristics and services.
+
+This script uses the registries to automatically generate documentation
+of all supported GATT characteristics and services.
+"""
+
+from __future__ import annotations
+
+import inspect
+import sys
+from pathlib import Path
+
+# Add src to path
+repo_root = Path(__file__).parent.parent
+sys.path.insert(0, str(repo_root / "src"))
+
+from bluetooth_sig.gatt.characteristics import CHARACTERISTIC_CLASS_MAP # noqa: E402
+from bluetooth_sig.gatt.resolver import NameNormalizer # noqa: E402
+from bluetooth_sig.gatt.services import SERVICE_CLASS_MAP # noqa: E402
+from bluetooth_sig.gatt.uuid_registry import uuid_registry # noqa: E402
+
+
+def get_characteristic_info(char_class: type) -> tuple[str, str, str]:
+ """Get UUID, name, and description for a characteristic class.
+
+ Args:
+ char_class: The characteristic class
+
+ Returns:
+ Tuple of (uuid, name, description)
+ """
+ try:
+ # Get UUID from the class method
+ uuid_obj = char_class.get_class_uuid()
+ uuid = str(uuid_obj).upper() if uuid_obj else "N/A"
+
+ # Try to get name from registry first (most accurate)
+ registry_info = uuid_registry.get_characteristic_info(uuid_obj) if uuid_obj else None
+ if registry_info:
+ name = registry_info.name
+ # Get description from docstring if registry doesn't have summary
+ description = registry_info.summary or ""
+ if not description:
+ doc = inspect.getdoc(char_class)
+ if doc:
+ description = doc.split("\n")[0].strip()
+ else:
+ # Fallback to class name processing
+ base_name = NameNormalizer.remove_suffix(char_class.__name__, "Characteristic")
+ name = NameNormalizer.camel_case_to_display_name(base_name)
+ doc = inspect.getdoc(char_class)
+ description = doc.split("\n")[0].strip() if doc else ""
+
+ return uuid, name, description
+ except Exception as e:
+ print(f"Warning: Error processing {char_class.__name__}: {e}", file=sys.stderr)
+ return "N/A", char_class.__name__, ""
+
+
+def get_service_info(service_class: type) -> tuple[str, str, str]:
+ """Get UUID, name, and description for a service class.
+
+ Args:
+ service_class: The service class
+
+ Returns:
+ Tuple of (uuid, name, description)
+ """
+ try:
+ # Get UUID from the class method
+ uuid_obj = service_class.get_class_uuid()
+ uuid = str(uuid_obj).upper() if uuid_obj else "N/A"
+
+ # Try to get name from registry first (most accurate)
+ registry_info = uuid_registry.get_service_info(uuid_obj) if uuid_obj else None
+ if registry_info:
+ name = registry_info.name
+ # Get description from docstring if registry doesn't have summary
+ description = registry_info.summary or ""
+ if not description:
+ doc = inspect.getdoc(service_class)
+ if doc:
+ description = doc.split("\n")[0].strip()
+ else:
+ # Fallback to class name processing
+ base_name = NameNormalizer.remove_suffix(service_class.__name__, "Service")
+ name = NameNormalizer.camel_case_to_display_name(base_name)
+ doc = inspect.getdoc(service_class)
+ description = doc.split("\n")[0].strip() if doc else ""
+
+ return uuid, name, description
+ except Exception as e:
+ print(f"Warning: Error processing {service_class.__name__}: {e}", file=sys.stderr)
+ return "N/A", service_class.__name__, ""
+
+
+def discover_characteristics() -> list[tuple[str, str, str, str]]:
+ """Discover all characteristic classes from the registry.
+
+ Returns:
+ List of tuples: (class_name, uuid, name, description)
+ """
+ characteristics = []
+
+ try:
+ # Use the characteristic class map directly
+ for _char_name, char_class in CHARACTERISTIC_CLASS_MAP.items():
+ uuid, name, description = get_characteristic_info(char_class)
+ characteristics.append((char_class.__name__, uuid, name, description))
+
+ except Exception as e:
+ print(f"Error discovering characteristics: {e}", file=sys.stderr)
+
+ # Sort by name
+ characteristics.sort(key=lambda x: x[2])
+ return characteristics
+
+
+def discover_services() -> list[tuple[str, str, str, str]]:
+ """Discover all service classes from the registry.
+
+ Returns:
+ List of tuples: (class_name, uuid, name, description)
+ """
+ services = []
+
+ try:
+ # Use the service class map directly
+ for _service_name, service_class in SERVICE_CLASS_MAP.items():
+ uuid, name, description = get_service_info(service_class)
+ services.append((service_class.__name__, uuid, name, description))
+
+ except Exception as e:
+ print(f"Error discovering services: {e}", file=sys.stderr)
+
+ # Sort by name
+ services.sort(key=lambda x: x[2])
+ return services
+
+
+def generate_markdown() -> str:
+ """Generate markdown documentation for characteristics and services."""
+
+ characteristics = discover_characteristics()
+ services = discover_services()
+
+ md = f"""# Supported Characteristics and Services
+
+This page lists all GATT characteristics and services currently supported by the library.
+
+!!! note "Auto-Generated"
+ This page is automatically generated from the codebase. The list is updated when new
+ characteristics or services are added.
+
+## Characteristics
+
+The library currently supports **{len(characteristics)}** GATT characteristics:
+"""
+
+ # Build a mapping of characteristic names to the services they belong to
+ # char_name -> [(service_name, service_uuid, service_class)]
+ char_to_services: dict[str, list[tuple[str, str, str]]] = {}
+
+ for service_class_name, service_uuid, service_name, _service_description in services:
+ # Get the actual service class to access its service_characteristics
+ try:
+ service_class = SERVICE_CLASS_MAP.get(service_name.replace(" ", "").upper())
+ if service_class is None:
+ # Try alternative lookup
+ for _key, cls in SERVICE_CLASS_MAP.items():
+ if cls.__name__ == service_class_name:
+ service_class = cls
+ break
+
+ if service_class and hasattr(service_class, 'service_characteristics'):
+ # Get the characteristics defined in this service
+ for char_name_enum in service_class.service_characteristics.keys():
+ # Convert enum to readable name
+ char_display_name = char_name_enum.value.replace("_", " ").title()
+
+ if char_display_name not in char_to_services:
+ char_to_services[char_display_name] = []
+
+ char_to_services[char_display_name].append((service_name, service_uuid, service_class_name))
+ except Exception as e:
+ print(f"Warning: Could not process service {service_class_name}: {e}", file=sys.stderr)
+ continue
+
+ # Group characteristics by service
+ # service_name -> [(class_name, uuid, name, description)]
+ service_groups: dict[str, list[tuple[str, str, str, str]]] = {}
+ ungrouped_chars: list[tuple[str, str, str, str]] = []
+
+ for class_name, uuid, name, description in characteristics:
+ if name in char_to_services:
+ # Add to each service that uses this characteristic
+ for service_name, _service_uuid, _service_class_name in char_to_services[name]:
+ if service_name not in service_groups:
+ service_groups[service_name] = []
+ service_groups[service_name].append((class_name, uuid, name, description))
+ else:
+ ungrouped_chars.append((class_name, uuid, name, description))
+
+ # Output characteristics grouped by service
+ # Sort services alphabetically
+ for service_name in sorted(service_groups.keys()):
+ chars_in_service = service_groups[service_name]
+ if not chars_in_service:
+ continue
+
+ md += f"\n### {service_name}\n\n"
+ md += "| Characteristic | UUID | Description |\n"
+ md += "|----------------|------|-------------|\n"
+
+ for _class_name, uuid, name, description in sorted(chars_in_service, key=lambda x: x[2]):
+ # Truncate long descriptions
+ if len(description) > 80:
+ description = description[:77] + "..."
+ md += f"| **{name}** | `{uuid}` | {description} |\n"
+
+ # Add ungrouped characteristics if any
+ if ungrouped_chars:
+ md += "\n### Other Characteristics\n\n"
+ md += "| Characteristic | UUID | Description |\n"
+ md += "|----------------|------|-------------|\n"
+
+ for _class_name, uuid, name, description in sorted(ungrouped_chars, key=lambda x: x[2]):
+ if len(description) > 80:
+ description = description[:77] + "..."
+ md += f"| **{name}** | `{uuid}` | {description} |\n"
+
+ md += "\n## Services\n\n"
+ md += f"The library currently supports **{len(services)}** GATT services:\n\n"
+ md += "| Service | UUID | Description |\n"
+ md += "|---------|------|-------------|\n"
+
+ for _class_name, uuid, name, description in services:
+ if len(description) > 100:
+ description = description[:97] + "..."
+ md += f"| **{name}** | `{uuid}` | {description} |\n"
+
+ md += """
+## Adding Support for New Characteristics
+
+To add support for a new characteristic:
+
+1. See the [Adding New Characteristics](guides/adding-characteristics.md) guide
+2. Follow the existing patterns in `src/bluetooth_sig/gatt/characteristics/`
+3. Add tests for your new characteristic
+4. Submit a pull request
+
+## Official Bluetooth SIG Registry
+
+This library is based on the official [Bluetooth SIG Assigned Numbers](https://www.bluetooth.com/specifications/assigned-numbers/)
+registry. The UUID registry is loaded from YAML files in the `bluetooth_sig` submodule.
+"""
+
+ return md
+
+
+def main() -> None:
+ """Main entry point."""
+ output_file = repo_root / "docs" / "supported-characteristics.md"
+
+ print("Generating characteristics and services list...")
+ markdown = generate_markdown()
+
+ print(f"Writing to {output_file}...")
+ output_file.write_text(markdown)
+
+ print("â Successfully generated documentation")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/scripts/generate_characteristics_list.py b/scripts/generate_characteristics_list.py
deleted file mode 100644
index 08b3426d..00000000
--- a/scripts/generate_characteristics_list.py
+++ /dev/null
@@ -1,250 +0,0 @@
-#!/usr/bin/env python3
-"""Generate a markdown file listing all supported characteristics and services.
-
-This script scans the codebase to automatically generate documentation
-of all supported GATT characteristics and services.
-"""
-
-import importlib
-import inspect
-import pkgutil
-import sys
-from pathlib import Path
-from typing import Dict, List, Tuple
-
-# Add src to path
-repo_root = Path(__file__).parent.parent
-sys.path.insert(0, str(repo_root / "src"))
-
-from bluetooth_sig.gatt.characteristics.base import BaseCharacteristic
-from bluetooth_sig.gatt.services.base import BaseGattService
-
-
-def get_characteristic_info(cls: type) -> Tuple[str, str, str]:
- """Get UUID, name, and description for a characteristic class."""
- try:
- # Try to get info from _info attribute
- if hasattr(cls, '_info') and cls._info is not None:
- uuid = getattr(cls._info, 'uuid', 'N/A')
- name = getattr(cls._info, 'name', cls.__name__)
- # Convert UUID object to string if needed
- uuid = str(uuid).upper() if uuid != 'N/A' else 'N/A'
- else:
- # Fallback to class attributes
- uuid = 'N/A'
- name = cls.__name__.replace('Characteristic', '').replace('_', ' ')
-
- # Get description from docstring
- doc = inspect.getdoc(cls)
- if doc:
- # Get first line as description
- description = doc.split('\n')[0].strip()
- else:
- description = ""
-
- return uuid, name, description
- except Exception as e:
- print(f"Warning: Error processing {cls.__name__}: {e}", file=sys.stderr)
- return 'N/A', cls.__name__, ""
-
-
-def discover_characteristics() -> List[Tuple[str, str, str, str]]:
- """Discover all characteristic classes.
-
- Returns:
- List of tuples: (class_name, uuid, name, description)
- """
- characteristics = []
-
- try:
- import bluetooth_sig.gatt.characteristics as chars_module
-
- # Get the package path
- package_path = Path(chars_module.__file__).parent
-
- # Iterate through all Python files in the characteristics directory
- for file_path in package_path.glob("*.py"):
- if file_path.name.startswith('_') or file_path.name in ['base.py', 'utils.py']:
- continue
-
- module_name = f"bluetooth_sig.gatt.characteristics.{file_path.stem}"
- try:
- module = importlib.import_module(module_name)
-
- # Find all classes that inherit from BaseCharacteristic
- for name, obj in inspect.getmembers(module, inspect.isclass):
- if (issubclass(obj, BaseCharacteristic) and
- obj is not BaseCharacteristic and
- obj.__module__ == module_name):
-
- uuid, char_name, description = get_characteristic_info(obj)
- characteristics.append((name, uuid, char_name, description))
- except Exception as e:
- print(f"Warning: Could not import {module_name}: {e}", file=sys.stderr)
-
- except Exception as e:
- print(f"Error discovering characteristics: {e}", file=sys.stderr)
-
- # Sort by name
- characteristics.sort(key=lambda x: x[2])
- return characteristics
-
-
-def discover_services() -> List[Tuple[str, str, str]]:
- """Discover all service classes.
-
- Returns:
- List of tuples: (class_name, name, description)
- """
- services = []
-
- try:
- import bluetooth_sig.gatt.services as services_module
-
- # Get the package path
- package_path = Path(services_module.__file__).parent
-
- # Iterate through all Python files in the services directory
- for file_path in package_path.glob("*.py"):
- if file_path.name.startswith('_') or file_path.name == 'base.py':
- continue
-
- module_name = f"bluetooth_sig.gatt.services.{file_path.stem}"
- try:
- module = importlib.import_module(module_name)
-
- # Find all classes that inherit from BaseGattService
- for name, obj in inspect.getmembers(module, inspect.isclass):
- if (issubclass(obj, BaseGattService) and
- obj is not BaseGattService and
- obj.__module__ == module_name):
-
- # Get description from docstring
- doc = inspect.getdoc(obj)
- description = doc.split('\n')[0].strip() if doc else ""
-
- service_name = name.replace('Service', '').replace('_', ' ')
- services.append((name, service_name, description))
- except Exception as e:
- print(f"Warning: Could not import {module_name}: {e}", file=sys.stderr)
-
- except Exception as e:
- print(f"Error discovering services: {e}", file=sys.stderr)
-
- # Sort by name
- services.sort(key=lambda x: x[1])
- return services
-
-
-def generate_markdown() -> str:
- """Generate markdown documentation for characteristics and services."""
-
- characteristics = discover_characteristics()
- services = discover_services()
-
- md = """# Supported Characteristics and Services
-
-This page lists all GATT characteristics and services currently supported by the library.
-
-!!! note "Auto-Generated"
- This page is automatically generated from the codebase. The list is updated when new characteristics or services are added.
-
-## Characteristics
-
-The library currently supports **{num_chars}** GATT characteristics:
-
-""".format(num_chars=len(characteristics))
-
- # Group by category based on common prefixes
- categories: Dict[str, List[Tuple[str, str, str, str]]] = {}
-
- for class_name, uuid, name, description in characteristics:
- # Try to categorize
- category = "Other"
-
- if any(x in name.lower() for x in ['battery', 'power']):
- category = "Power & Battery"
- elif any(x in name.lower() for x in ['temperature', 'humidity', 'pressure', 'uv', 'co2', 'pm', 'air']):
- category = "Environmental Sensing"
- elif any(x in name.lower() for x in ['heart', 'blood', 'glucose', 'weight', 'body']):
- category = "Health & Fitness"
- elif any(x in name.lower() for x in ['cycling', 'running', 'rsc', 'csc']):
- category = "Sports & Activity"
- elif any(x in name.lower() for x in ['manufacturer', 'model', 'serial', 'firmware', 'hardware', 'software']):
- category = "Device Information"
- elif any(x in name.lower() for x in ['current', 'voltage', 'electric']):
- category = "Electrical"
-
- if category not in categories:
- categories[category] = []
- categories[category].append((class_name, uuid, name, description))
-
- # Sort categories
- category_order = [
- "Power & Battery",
- "Environmental Sensing",
- "Health & Fitness",
- "Sports & Activity",
- "Device Information",
- "Electrical",
- "Other"
- ]
-
- for category in category_order:
- if category not in categories or not categories[category]:
- continue
-
- md += f"\n### {category}\n\n"
- md += "| Characteristic | UUID | Description |\n"
- md += "|----------------|------|-------------|\n"
-
- for class_name, uuid, name, description in sorted(categories[category], key=lambda x: x[2]):
- # Truncate long descriptions
- if len(description) > 80:
- description = description[:77] + "..."
- md += f"| **{name}** | `{uuid}` | {description} |\n"
-
- md += "\n## Services\n\n"
- md += f"The library currently supports **{len(services)}** GATT services:\n\n"
- md += "| Service | Description |\n"
- md += "|---------|-------------|\n"
-
- for class_name, name, description in services:
- if len(description) > 100:
- description = description[:97] + "..."
- md += f"| **{name}** | {description} |\n"
-
- md += """
-
-## Adding Support for New Characteristics
-
-To add support for a new characteristic:
-
-1. See the [Adding New Characteristics](guides/adding-characteristics.md) guide
-2. Follow the existing patterns in `src/bluetooth_sig/gatt/characteristics/`
-3. Add tests for your new characteristic
-4. Submit a pull request
-
-## Official Bluetooth SIG Registry
-
-This library is based on the official [Bluetooth SIG Assigned Numbers](https://www.bluetooth.com/specifications/assigned-numbers/) registry. The UUID registry is loaded from YAML files in the `bluetooth_sig` submodule.
-"""
-
- return md
-
-
-def main():
- """Main entry point."""
- output_file = repo_root / "docs" / "supported-characteristics.md"
-
- print(f"Generating characteristics and services list...")
- markdown = generate_markdown()
-
- print(f"Writing to {output_file}...")
- output_file.write_text(markdown)
-
- print(f"â Successfully generated documentation")
-
-
-if __name__ == "__main__":
- main()
diff --git a/src/bluetooth_sig/core/translator.py b/src/bluetooth_sig/core/translator.py
index 3fccdb9a..38972664 100644
--- a/src/bluetooth_sig/core/translator.py
+++ b/src/bluetooth_sig/core/translator.py
@@ -327,7 +327,7 @@ def clear_services(self) -> None:
"""Clear all discovered services."""
self._services.clear()
- def resolve_uuid(self, name: str) -> SIGInfo | None:
+ def resolve_by_name(self, name: str) -> SIGInfo | None:
"""Resolve a characteristic or service name to its full info.
Args:
@@ -363,7 +363,7 @@ def resolve_uuid(self, name: str) -> SIGInfo | None:
return None
- def resolve_name(self, uuid: str) -> SIGInfo | None:
+ def resolve_by_uuid(self, uuid: str) -> SIGInfo | None:
"""Resolve a UUID to its full SIG information.
Args:
diff --git a/src/bluetooth_sig/gatt/uuid_registry.py b/src/bluetooth_sig/gatt/uuid_registry.py
index 823d2157..3bffc38b 100644
--- a/src/bluetooth_sig/gatt/uuid_registry.py
+++ b/src/bluetooth_sig/gatt/uuid_registry.py
@@ -170,6 +170,9 @@ def _generate_aliases(self, info: UuidInfo) -> set[str]:
service_name = service_name[:-8] # Remove _service
service_name = service_name.replace("_", " ").title()
aliases.add(service_name)
+ # Also add "Service" suffix if not present
+ if not service_name.endswith(" Service"):
+ aliases.add(service_name + " Service")
elif "characteristic" in info.id:
char_name = info.id.replace("org.bluetooth.characteristic.", "")
char_name = char_name.replace("_", " ").title()
diff --git a/tests/test_bluetooth_sig_translator.py b/tests/test_bluetooth_sig_translator.py
index f753f53c..e3e73021 100644
--- a/tests/test_bluetooth_sig_translator.py
+++ b/tests/test_bluetooth_sig_translator.py
@@ -140,13 +140,13 @@ def test_resolve_uuid_with_characteristic_name(self) -> None:
translator = BluetoothSIGTranslator()
# Test known characteristic
- result = translator.resolve_uuid("Battery Level")
+ result = translator.resolve_by_name("Battery Level")
assert result is not None, "Should find Battery Level characteristic"
assert result.uuid == "2A19", f"Expected 2A19, got {result.uuid}"
assert result.name == "Battery Level"
# Test unknown characteristic
- result = translator.resolve_uuid("Unknown Characteristic")
+ result = translator.resolve_by_name("Unknown Characteristic")
assert result is None
def test_resolve_name_with_uuid(self) -> None:
@@ -154,13 +154,13 @@ def test_resolve_name_with_uuid(self) -> None:
translator = BluetoothSIGTranslator()
# Test known UUID
- result = translator.resolve_name("2A19")
+ result = translator.resolve_by_uuid("2A19")
assert result is not None, "Should find info for 2A19"
assert result.name == "Battery Level", f"Expected 'Battery Level', got {result.name}"
assert result.uuid == "2A19"
# Test unknown UUID
- result = translator.resolve_name("FFFF")
+ result = translator.resolve_by_uuid("FFFF")
assert result is None
def test_parse_characteristics_batch(self) -> None: