mirror of
https://github.com/home-assistant/core.git
synced 2025-07-14 08:47:10 +00:00
Add helper method to get matter device info (#103765)
* Add helper method to get matter device info * Cleanup async * Guard * get node from device id instead of node id * Fix test --------- Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
parent
e157206eeb
commit
ebdd2daab6
@ -3,6 +3,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
|
from functools import cache
|
||||||
|
|
||||||
from matter_server.client import MatterClient
|
from matter_server.client import MatterClient
|
||||||
from matter_server.client.exceptions import CannotConnect, InvalidServerVersion
|
from matter_server.client.exceptions import CannotConnect, InvalidServerVersion
|
||||||
@ -28,12 +29,34 @@ from .addon import get_addon_manager
|
|||||||
from .api import async_register_api
|
from .api import async_register_api
|
||||||
from .const import CONF_INTEGRATION_CREATED_ADDON, CONF_USE_ADDON, DOMAIN, LOGGER
|
from .const import CONF_INTEGRATION_CREATED_ADDON, CONF_USE_ADDON, DOMAIN, LOGGER
|
||||||
from .discovery import SUPPORTED_PLATFORMS
|
from .discovery import SUPPORTED_PLATFORMS
|
||||||
from .helpers import MatterEntryData, get_matter, get_node_from_device_entry
|
from .helpers import (
|
||||||
|
MatterEntryData,
|
||||||
|
get_matter,
|
||||||
|
get_node_from_device_entry,
|
||||||
|
node_from_ha_device_id,
|
||||||
|
)
|
||||||
|
from .models import MatterDeviceInfo
|
||||||
|
|
||||||
CONNECT_TIMEOUT = 10
|
CONNECT_TIMEOUT = 10
|
||||||
LISTEN_READY_TIMEOUT = 30
|
LISTEN_READY_TIMEOUT = 30
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
@cache
|
||||||
|
def get_matter_device_info(
|
||||||
|
hass: HomeAssistant, device_id: str
|
||||||
|
) -> MatterDeviceInfo | None:
|
||||||
|
"""Return Matter device info or None if device does not exist."""
|
||||||
|
if not (node := node_from_ha_device_id(hass, device_id)):
|
||||||
|
return None
|
||||||
|
|
||||||
|
return MatterDeviceInfo(
|
||||||
|
unique_id=node.device_info.uniqueID,
|
||||||
|
vendor_id=hex(node.device_info.vendorID),
|
||||||
|
product_id=hex(node.device_info.productID),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
"""Set up Matter from a config entry."""
|
"""Set up Matter from a config entry."""
|
||||||
if use_addon := entry.data.get(CONF_USE_ADDON):
|
if use_addon := entry.data.get(CONF_USE_ADDON):
|
||||||
@ -190,7 +213,7 @@ async def async_remove_config_entry_device(
|
|||||||
hass: HomeAssistant, config_entry: ConfigEntry, device_entry: dr.DeviceEntry
|
hass: HomeAssistant, config_entry: ConfigEntry, device_entry: dr.DeviceEntry
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Remove a config entry from a device."""
|
"""Remove a config entry from a device."""
|
||||||
node = await get_node_from_device_entry(hass, device_entry)
|
node = get_node_from_device_entry(hass, device_entry)
|
||||||
|
|
||||||
if node is None:
|
if node is None:
|
||||||
return True
|
return True
|
||||||
@ -218,21 +241,11 @@ async def async_remove_config_entry_device(
|
|||||||
def _async_init_services(hass: HomeAssistant) -> None:
|
def _async_init_services(hass: HomeAssistant) -> None:
|
||||||
"""Init services."""
|
"""Init services."""
|
||||||
|
|
||||||
async def _node_id_from_ha_device_id(ha_device_id: str) -> int | None:
|
|
||||||
"""Get node id from ha device id."""
|
|
||||||
dev_reg = dr.async_get(hass)
|
|
||||||
device = dev_reg.async_get(ha_device_id)
|
|
||||||
if device is None:
|
|
||||||
return None
|
|
||||||
if node := await get_node_from_device_entry(hass, device):
|
|
||||||
return node.node_id
|
|
||||||
return None
|
|
||||||
|
|
||||||
async def open_commissioning_window(call: ServiceCall) -> None:
|
async def open_commissioning_window(call: ServiceCall) -> None:
|
||||||
"""Open commissioning window on specific node."""
|
"""Open commissioning window on specific node."""
|
||||||
node_id = await _node_id_from_ha_device_id(call.data["device_id"])
|
node = node_from_ha_device_id(hass, call.data["device_id"])
|
||||||
|
|
||||||
if node_id is None:
|
if node is None:
|
||||||
raise HomeAssistantError("This is not a Matter device")
|
raise HomeAssistantError("This is not a Matter device")
|
||||||
|
|
||||||
matter_client = get_matter(hass).matter_client
|
matter_client = get_matter(hass).matter_client
|
||||||
@ -240,7 +253,7 @@ def _async_init_services(hass: HomeAssistant) -> None:
|
|||||||
# We are sending device ID .
|
# We are sending device ID .
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await matter_client.open_commissioning_window(node_id)
|
await matter_client.open_commissioning_window(node.node_id)
|
||||||
except NodeCommissionFailed as err:
|
except NodeCommissionFailed as err:
|
||||||
raise HomeAssistantError(str(err)) from err
|
raise HomeAssistantError(str(err)) from err
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ async def async_get_device_diagnostics(
|
|||||||
"""Return diagnostics for a device."""
|
"""Return diagnostics for a device."""
|
||||||
matter = get_matter(hass)
|
matter = get_matter(hass)
|
||||||
server_diagnostics = await matter.matter_client.get_diagnostics()
|
server_diagnostics = await matter.matter_client.get_diagnostics()
|
||||||
node = await get_node_from_device_entry(hass, device)
|
node = get_node_from_device_entry(hass, device)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"server_info": dataclass_to_dict(server_diagnostics.info),
|
"server_info": dataclass_to_dict(server_diagnostics.info),
|
||||||
|
@ -66,7 +66,18 @@ def get_device_id(
|
|||||||
return f"{operational_instance_id}-{postfix}"
|
return f"{operational_instance_id}-{postfix}"
|
||||||
|
|
||||||
|
|
||||||
async def get_node_from_device_entry(
|
@callback
|
||||||
|
def node_from_ha_device_id(hass: HomeAssistant, ha_device_id: str) -> MatterNode | None:
|
||||||
|
"""Get node id from ha device id."""
|
||||||
|
dev_reg = dr.async_get(hass)
|
||||||
|
device = dev_reg.async_get(ha_device_id)
|
||||||
|
if device is None:
|
||||||
|
raise ValueError("Invalid device ID")
|
||||||
|
return get_node_from_device_entry(hass, device)
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def get_node_from_device_entry(
|
||||||
hass: HomeAssistant, device: dr.DeviceEntry
|
hass: HomeAssistant, device: dr.DeviceEntry
|
||||||
) -> MatterNode | None:
|
) -> MatterNode | None:
|
||||||
"""Return MatterNode from device entry."""
|
"""Return MatterNode from device entry."""
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from typing import TypedDict
|
||||||
|
|
||||||
from chip.clusters import Objects as clusters
|
from chip.clusters import Objects as clusters
|
||||||
from chip.clusters.Objects import ClusterAttributeDescriptor
|
from chip.clusters.Objects import ClusterAttributeDescriptor
|
||||||
@ -16,6 +17,20 @@ SensorValueTypes = type[
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class MatterDeviceInfo(TypedDict):
|
||||||
|
"""Dictionary with Matter Device info.
|
||||||
|
|
||||||
|
Used to send to other Matter controllers,
|
||||||
|
such as Google Home to prevent duplicated devices.
|
||||||
|
|
||||||
|
Reference: https://developers.home.google.com/matter/device-deduplication
|
||||||
|
"""
|
||||||
|
|
||||||
|
unique_id: str
|
||||||
|
vendor_id: str # vendorId hex string
|
||||||
|
product_id: str # productId hex string
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class MatterEntityInfo:
|
class MatterEntityInfo:
|
||||||
"""Info discovered from (primary) Matter Attribute to create entity."""
|
"""Info discovered from (primary) Matter Attribute to create entity."""
|
||||||
|
@ -56,7 +56,7 @@ async def test_get_node_from_device_entry(
|
|||||||
device_registry, config_entry.entry_id
|
device_registry, config_entry.entry_id
|
||||||
)[0]
|
)[0]
|
||||||
assert device_entry
|
assert device_entry
|
||||||
node_from_device_entry = await get_node_from_device_entry(hass, device_entry)
|
node_from_device_entry = get_node_from_device_entry(hass, device_entry)
|
||||||
|
|
||||||
assert node_from_device_entry is node
|
assert node_from_device_entry is node
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user