网络和发现
某些集成可能需要通过 mDNS/Zeroconf、SSDP 或其它已启用的方式来发现网络中的设备。最常见的场景包括:查找没有固定 IP 地址的设备,或者为可动态增删任意数量兼容设备的集成提供发现能力。
Home Assistant 内置了对 mDNS/Zeroconf 和 SSDP 的 helper。如果你的集成使用其它发现方式,并且需要决定应通过哪些网络接口广播流量,可以使用 network 集成提供的 helper API 来访问用户的网络接口偏好设置。
mDNS/Zeroconf
Home Assistant 使用 python-zeroconf 提供 mDNS 支持。由于不建议在同一台主机上运行多个 mDNS 实现,Home Assistant 提供了内部 helper API,用于访问正在运行的 Zeroconf 和 AsyncZeroconf 实例。
在使用这些 helper 之前,请先在集成的 manifest.json 中把 zeroconf 添加到 dependencies,参见 manifest.json。
获取 AsyncZeroconf 对象
from homeassistant.components import zeroconf
...
aiozc = await zeroconf.async_get_async_instance(hass)
获取 Zeroconf 对象
from homeassistant.components import zeroconf
...
zc = await zeroconf.async_get_instance(hass)
使用 AsyncZeroconf 和 Zeroconf 对象
python-zeroconf 提供了这两个对象的使用示例。
SSDP
Home Assistant 内置了 SSDP 发现能力。
在使用这些 helper 之前,请先在集成的 manifest.json 中把 ssdp 添加到 dependencies,参见 manifest.json。
获取已发现设备列表
SSDP 集成提供了以下 helper API,用于从缓存中获取已发现的 SSDP 设备:ssdp.async_get_discovery_info_by_udn_st、ssdp.async_get_discovery_info_by_st、ssdp.async_get_discovery_info_by_udn。
查找特定设备
ssdp.async_get_discovery_info_by_udn_st 在提供 UDN 和 ST 时,会返回单个 discovery_info,如果没有匹配则返回 None。
from homeassistant.components import ssdp
...
discovery_info = await ssdp.async_get_discovery_info_by_udn_st(hass, udn, st)
通过 ST 查找设备
如果你想查找已发现的特定类型设备,可以调用 ssdp.async_get_discovery_info_by_st。它会返回所有匹配该 ST 的已发现设备列表。下面的示例会返回网络上发现的每一台 Sonos 播放器的发现信息。
from homeassistant.components import ssdp
...
discovery_infos = await ssdp.async_get_discovery_info_by_st(hass, "urn:schemas-upnp-org:device:ZonePlayer:1")
for discovery_info in discovery_infos:
...
通过 UDN 查找设备
如果你想查看某个特定 UDN 提供的服务列表,可以调用 ssdp.async_get_discovery_info_by_udn。它会返回所有匹配该 UDN 的已发现设备列表。
from homeassistant.components import ssdp
...
discovery_infos = await ssdp.async_get_discovery_info_by_udn(hass, udn)
for discovery_info in discovery_infos:
...
订阅 SSDP 发现事件
某些集成可能需要在设备一被发现时就立即获知。SSDP 集成提供了注册 API,可在发现与指定键值匹配的新设备时触发回调。匹配格式与 manifest.json 中 ssdp 的配置格式一致,参见 manifest.json。
可通过 ssdp.async_register_callback 启用该功能。该函数会返回一个取消注册用的 callback。
下面的示例展示了如何在网络中发现 Sonos 播放器时接收回调。
from homeassistant.components import ssdp
...
entry.async_on_unload(
ssdp.async_register_callback(
hass, _async_discovered_player, {"st": "urn:schemas-upnp-org:device:ZonePlayer:1"}
)
)
下面的示例展示了如何在检测到 x-rincon-bootseq 头时接收回调。
from homeassistant.components import ssdp
from homeassistant.const import MATCH_ALL
...
entry.async_on_unload(
ssdp.async_register_callback(
hass, _async_discovered_player, {"x-rincon-bootseq": MATCH_ALL}
)
)
网络
对于使用非内置发现方式、并且需要访问用户网络适配器配置的集成,可以使用以下 helper API。
from homeassistant.components import network
...
adapters = await network.async_get_adapters(hass)
async_get_adapters 数据结构示例
[
{
"auto": True,
"default": False,
"enabled": True,
"ipv4": [],
"ipv6": [
{
"address": "2001:db8::",
"network_prefix": 8,
"flowinfo": 1,
"scope_id": 1,
}
],
"name": "eth0",
},
{
"auto": True,
"default": False,
"enabled": True,
"ipv4": [{"address": "192.168.1.5", "network_prefix": 23}],
"ipv6": [],
"name": "eth1",
},
{
"auto": False,
"default": False,
"enabled": False,
"ipv4": [{"address": "169.254.3.2", "network_prefix": 16}],
"ipv6": [],
"name": "vtun0",
},
]
从适配器获取 IP 网络
from ipaddress import ip_network
from homeassistant.components import network
...
adapters = await network.async_get_adapters(hass)
for adapter in adapters:
for ip_info in adapter["ipv4"]:
local_ip = ip_info["address"]
network_prefix = ip_info["network_prefix"]
ip_net = ip_network(f"{local_ip}/{network_prefix}", False)
USB
USB 集成会在启动时、打开集成页面时,以及插入新设备时(如果底层系统支持 pyudev)发现新的 USB 设备。
检查特定适配器是否已插入
调用 async_is_plugged_in API,检查系统中是否存在指定适配器。
from homeassistant.components import usb
...
if not usb.async_is_plugged_in(hass, {"serial_number": "A1234", "manufacturer": "xtech"}):
raise ConfigEntryNotReady("The USB device is missing")
了解何时需要查找新的兼容 USB 设备
当有新的兼容 USB 设备可用时,可调用 async_register_scan_request_callback API 注册回调。
from homeassistant.components import usb
from homeassistant.core import callback
...
@callback
def _async_check_for_usb() -> None:
"""Check for new compatible bluetooth USB adapters."""
entry.async_on_unload(
bluetooth.async_register_scan_request_callback(hass, _async_check_for_usb)
)