新增功能: - 配网管理模块 (provisioning.py): 支持设备扫描、配网、超时处理 - 配网配置步骤: UI 配置流程增加配网参数配置(Network Key, App Key 等) - 分组管理:支持 SIG 分组和 VENDOR 分组的加入/删除操作 - HA 服务调用:7 个配网和分组相关的服务 文件变更: - const.py: 添加配网相关常量(CONF_NETWORK_KEY, PROV_TIMEOUT 等) - config_flow.py: 增加 prov_config 配置步骤和 OptionsFlow 菜单 - provisioning.py: 新建配网管理器(ProvisioningManager 类) - coordinator.py: 集成配网管理器,添加配网状态管理方法 - services.py: 新建服务定义和注册 - services.yaml: HA 服务定义文件 - __init__.py: 集成服务注册和卸载 - PRD.md: 更新服务调用接口和配置参数文档 配网功能说明: - 首次使用需配置 Network Key, App Key, Network ID, IV Index - 配网超时时间:180 秒 - 组地址范围:0xC000 - 0xCFFF - 支持 SIG 标准分组和 VENDOR 自定义分组
187 lines
6.2 KiB
Python
187 lines
6.2 KiB
Python
"""SigMesh Gateway 服务定义。"""
|
|
|
|
import voluptuous as vol
|
|
from homeassistant.helpers import config_validation as cv
|
|
|
|
from .const import CONF_GROUP_ADDRESS, CONF_NETWORK_KEY, DOMAIN
|
|
|
|
# 服务常量
|
|
SERVICE_START_SCAN = "start_scan"
|
|
SERVICE_STOP_PROVISIONING = "stop_provisioning"
|
|
SERVICE_START_PROVISIONING = "start_provisioning"
|
|
SERVICE_BIND_APPKEY = "bind_appkey"
|
|
SERVICE_ADD_TO_GROUP = "add_to_group"
|
|
SERVICE_REMOVE_FROM_GROUP = "remove_from_group"
|
|
SERVICE_SEND_VENDOR_COMMAND = "send_vendor_command"
|
|
|
|
# 服务 Schema
|
|
SERVICE_SCHEMA_START_SCAN = {}
|
|
|
|
SERVICE_SCHEMA_STOP_PROVISIONING = {}
|
|
|
|
SERVICE_SCHEMA_START_PROVISIONING = {
|
|
vol.Required("device_address"): cv.string,
|
|
}
|
|
|
|
SERVICE_SCHEMA_BIND_APPKEY = {
|
|
vol.Required("device_address"): cv.string,
|
|
vol.Required("element_address", default=0): vol.Coerce(int),
|
|
}
|
|
|
|
SERVICE_SCHEMA_ADD_TO_GROUP = {
|
|
vol.Required("target_address"): cv.string,
|
|
vol.Required("element_address", default=0): vol.Coerce(int),
|
|
vol.Required("group_address"): cv.string,
|
|
vol.Required("model_id", default=4352): vol.Coerce(int),
|
|
vol.Optional("is_sig", default=True): cv.boolean,
|
|
}
|
|
|
|
SERVICE_SCHEMA_REMOVE_FROM_GROUP = {
|
|
vol.Required("target_address"): cv.string,
|
|
vol.Required("element_address", default=0): vol.Coerce(int),
|
|
vol.Required("group_address"): cv.string,
|
|
vol.Required("model_id", default=4352): vol.Coerce(int),
|
|
vol.Optional("is_sig", default=True): cv.boolean,
|
|
}
|
|
|
|
SERVICE_SCHEMA_SEND_VENDOR_COMMAND = {
|
|
vol.Required("target_address"): cv.string,
|
|
vol.Required("element_address", default=0): vol.Coerce(int),
|
|
vol.Required("opcode"): cv.string,
|
|
vol.Required("payload"): cv.string,
|
|
}
|
|
|
|
|
|
def setup_services(hass, coordinators: dict) -> None:
|
|
"""设置 HA 服务。
|
|
|
|
Args:
|
|
hass: HomeAssistant 实例
|
|
coordinators: 协调器字典 {entry_id: coordinator}
|
|
"""
|
|
|
|
async def handle_start_scan(call) -> None:
|
|
"""处理开始扫描服务调用."""
|
|
for coordinator in coordinators.values():
|
|
await coordinator.start_scanning()
|
|
|
|
async def handle_stop_provisioning(call) -> None:
|
|
"""处理停止配网服务调用."""
|
|
for coordinator in coordinators.values():
|
|
await coordinator.stop_provisioning()
|
|
|
|
async def handle_start_provisioning(call) -> None:
|
|
"""处理开始配网服务调用."""
|
|
device_address = call.data.get("device_address")
|
|
for coordinator in coordinators.values():
|
|
await coordinator.start_provisioning(device_address)
|
|
|
|
async def handle_bind_appkey(call) -> None:
|
|
"""处理绑定 App Key 服务调用."""
|
|
device_address = call.data.get("device_address")
|
|
element_address = call.data.get("element_address", 0)
|
|
for coordinator in coordinators.values():
|
|
await coordinator.bind_app_key(device_address, element_address)
|
|
|
|
async def handle_add_to_group(call) -> None:
|
|
"""处理添加设备到组服务调用."""
|
|
target_address = call.data.get("target_address")
|
|
element_address = call.data.get("element_address", 0)
|
|
group_address = call.data.get("group_address")
|
|
model_id = call.data.get("model_id", 4352)
|
|
is_sig = call.data.get("is_sig", True)
|
|
|
|
# 解析组地址(支持 hex 字符串)
|
|
if isinstance(group_address, str):
|
|
group_address = int(group_address, 16)
|
|
|
|
for coordinator in coordinators.values():
|
|
await coordinator.add_device_to_group(
|
|
target_address, element_address, group_address, model_id, is_sig
|
|
)
|
|
|
|
async def handle_remove_from_group(call) -> None:
|
|
"""处理从组中移除设备服务调用."""
|
|
target_address = call.data.get("target_address")
|
|
element_address = call.data.get("element_address", 0)
|
|
group_address = call.data.get("group_address")
|
|
model_id = call.data.get("model_id", 4352)
|
|
is_sig = call.data.get("is_sig", True)
|
|
|
|
# 解析组地址(支持 hex 字符串)
|
|
if isinstance(group_address, str):
|
|
group_address = int(group_address, 16)
|
|
|
|
for coordinator in coordinators.values():
|
|
await coordinator.remove_device_from_group(
|
|
target_address, element_address, group_address, model_id, is_sig
|
|
)
|
|
|
|
async def handle_send_vendor_command(call) -> None:
|
|
"""处理发送 VENDOR 命令服务调用."""
|
|
target_address = call.data.get("target_address")
|
|
element_address = call.data.get("element_address", 0)
|
|
opcode = call.data.get("opcode")
|
|
payload = call.data.get("payload")
|
|
|
|
# 解析操作码和负载
|
|
if isinstance(opcode, str):
|
|
opcode = int(opcode, 16)
|
|
if isinstance(payload, str):
|
|
payload = bytes.fromhex(payload)
|
|
|
|
for coordinator in coordinators.values():
|
|
await coordinator.prov_manager.send_vendor_command(
|
|
target_address, element_address, opcode, payload
|
|
)
|
|
|
|
# 注册服务
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
SERVICE_START_SCAN,
|
|
handle_start_scan,
|
|
schema=vol.Schema(SERVICE_SCHEMA_START_SCAN),
|
|
)
|
|
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
SERVICE_STOP_PROVISIONING,
|
|
handle_stop_provisioning,
|
|
schema=vol.Schema(SERVICE_SCHEMA_STOP_PROVISIONING),
|
|
)
|
|
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
SERVICE_START_PROVISIONING,
|
|
handle_start_provisioning,
|
|
schema=vol.Schema(SERVICE_SCHEMA_START_PROVISIONING),
|
|
)
|
|
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
SERVICE_BIND_APPKEY,
|
|
handle_bind_appkey,
|
|
schema=vol.Schema(SERVICE_SCHEMA_BIND_APPKEY),
|
|
)
|
|
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
SERVICE_ADD_TO_GROUP,
|
|
handle_add_to_group,
|
|
schema=vol.Schema(SERVICE_SCHEMA_ADD_TO_GROUP),
|
|
)
|
|
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
SERVICE_REMOVE_FROM_GROUP,
|
|
handle_remove_from_group,
|
|
schema=vol.Schema(SERVICE_SCHEMA_REMOVE_FROM_GROUP),
|
|
)
|
|
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
SERVICE_SEND_VENDOR_COMMAND,
|
|
handle_send_vendor_command,
|
|
schema=vol.Schema(SERVICE_SCHEMA_SEND_VENDOR_COMMAND),
|
|
)
|