Coverage for src/bluetooth_sig/registry/mesh_profiles.py: 75%
48 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-30 00:10 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-30 00:10 +0000
1"""Mesh profiles registry for Bluetooth SIG mesh profile definitions."""
3from __future__ import annotations
5import msgspec
7from bluetooth_sig.registry.base import BaseRegistry
8from bluetooth_sig.registry.utils import find_bluetooth_sig_path, load_yaml_uuids, parse_bluetooth_uuid
9from bluetooth_sig.types.uuid import BluetoothUUID
12class MeshProfileInfo(msgspec.Struct, frozen=True, kw_only=True):
13 """Information about a Bluetooth SIG mesh profile."""
15 uuid: BluetoothUUID
16 name: str
17 id: str
20class MeshProfilesRegistry(BaseRegistry[MeshProfileInfo]):
21 """Registry for Bluetooth SIG mesh profile definitions."""
23 def __init__(self) -> None:
24 """Initialize the mesh profiles registry."""
25 super().__init__()
26 self._mesh_profiles: dict[str, MeshProfileInfo] = {}
27 self._name_to_info: dict[str, MeshProfileInfo] = {}
28 self._id_to_info: dict[str, MeshProfileInfo] = {}
29 self._load_mesh_profiles()
31 def _load_mesh_profiles(self) -> None:
32 """Load mesh profiles from the Bluetooth SIG YAML file."""
33 base_path = find_bluetooth_sig_path()
34 if not base_path:
35 return
37 # Load mesh profile UUIDs
38 mesh_profiles_yaml = base_path / "mesh_profiles.yaml"
39 if mesh_profiles_yaml.exists():
40 for item in load_yaml_uuids(mesh_profiles_yaml):
41 try:
42 uuid = parse_bluetooth_uuid(item["uuid"])
43 name = item["name"]
44 mesh_profile_id = item["id"]
46 info = MeshProfileInfo(uuid=uuid, name=name, id=mesh_profile_id)
48 # Store by UUID string for fast lookup
49 self._mesh_profiles[uuid.short_form.upper()] = info
50 self._name_to_info[name.lower()] = info
51 self._id_to_info[mesh_profile_id] = info
53 except (KeyError, ValueError):
54 # Skip malformed entries
55 continue
57 def get_mesh_profile_info(self, uuid: str | int | BluetoothUUID) -> MeshProfileInfo | None:
58 """Get mesh profile information by UUID.
60 Args:
61 uuid: The UUID to look up (string, int, or BluetoothUUID)
63 Returns:
64 MeshProfileInfo if found, None otherwise
65 """
66 try:
67 bt_uuid = parse_bluetooth_uuid(uuid)
68 return self._mesh_profiles.get(bt_uuid.short_form.upper())
69 except ValueError:
70 return None
72 def get_mesh_profile_info_by_name(self, name: str) -> MeshProfileInfo | None:
73 """Get mesh profile information by name (case insensitive).
75 Args:
76 name: The mesh profile name to look up
78 Returns:
79 MeshProfileInfo if found, None otherwise
80 """
81 return self._name_to_info.get(name.lower())
83 def get_mesh_profile_info_by_id(self, mesh_profile_id: str) -> MeshProfileInfo | None:
84 """Get mesh profile information by mesh profile ID.
86 Args:
87 mesh_profile_id: The mesh profile ID to look up
89 Returns:
90 MeshProfileInfo if found, None otherwise
91 """
92 return self._id_to_info.get(mesh_profile_id)
94 def is_mesh_profile_uuid(self, uuid: str | int | BluetoothUUID) -> bool:
95 """Check if a UUID corresponds to a known mesh profile.
97 Args:
98 uuid: The UUID to check
100 Returns:
101 True if the UUID is a known mesh profile, False otherwise
102 """
103 return self.get_mesh_profile_info(uuid) is not None
105 def get_all_mesh_profiles(self) -> list[MeshProfileInfo]:
106 """Get all mesh profiles in the registry.
108 Returns:
109 List of all MeshProfileInfo objects
110 """
111 return list(self._mesh_profiles.values())
114# Global instance for convenience
115mesh_profiles_registry = MeshProfilesRegistry.get_instance()