"""设备端IoT工具执行器""" import json import asyncio from typing import Dict, Any from ..base import ToolType, ToolDefinition, ToolExecutor from plugins_func.register import Action, ActionResponse class DeviceIoTExecutor(ToolExecutor): """设备端IoT工具执行器""" def __init__(self, conn): self.conn = conn self.iot_tools: Dict[str, ToolDefinition] = {} async def execute( self, conn, tool_name: str, arguments: Dict[str, Any] ) -> ActionResponse: """执行设备端IoT工具""" if not self.has_tool(tool_name): return ActionResponse( action=Action.NOTFOUND, response=f"IoT工具 {tool_name} 不存在" ) try: # 解析工具名称,获取设备名和操作类型 if tool_name.startswith("get_"): # 查询操作:get_devicename_property parts = tool_name.split("_", 2) if len(parts) >= 3: device_name = parts[1] property_name = parts[2] value = await self._get_iot_status(device_name, property_name) if value is not None: # 处理响应模板 response_success = arguments.get( "response_success", "查询成功:{value}" ) response = response_success.replace("{value}", str(value)) return ActionResponse( action=Action.RESPONSE, response=response, ) else: response_failure = arguments.get( "response_failure", f"无法获取{device_name}的状态" ) return ActionResponse( action=Action.ERROR, response=response_failure ) else: # 控制操作:devicename_method parts = tool_name.split("_", 1) if len(parts) >= 2: device_name = parts[0] method_name = parts[1] # 提取控制参数(排除响应参数) control_params = { k: v for k, v in arguments.items() if k not in ["response_success", "response_failure"] } # 发送IoT控制命令 await self._send_iot_command( device_name, method_name, control_params ) # 等待状态更新 await asyncio.sleep(0.1) response_success = arguments.get("response_success", "操作成功") # 处理响应中的占位符 for param_name, param_value in control_params.items(): placeholder = "{" + param_name + "}" if placeholder in response_success: response_success = response_success.replace( placeholder, str(param_value) ) if "{value}" in response_success: response_success = response_success.replace( "{value}", str(param_value) ) break return ActionResponse( action=Action.REQLLM, result=response_success, ) return ActionResponse(action=Action.ERROR, response="无法解析IoT工具名称") except Exception as e: response_failure = arguments.get("response_failure", "操作失败") return ActionResponse(action=Action.ERROR, response=response_failure) async def _get_iot_status(self, device_name: str, property_name: str): """获取IoT设备状态""" for key, value in self.conn.iot_descriptors.items(): if key.lower() == device_name.lower(): for property_item in value.properties: if property_item["name"].lower() == property_name.lower(): return property_item["value"] return None async def _send_iot_command( self, device_name: str, method_name: str, parameters: Dict[str, Any] ): """发送IoT控制命令""" for key, value in self.conn.iot_descriptors.items(): if key.lower() == device_name.lower(): for method in value.methods: if method["name"].lower() == method_name.lower(): command = { "name": key, "method": method["name"], } if parameters: command["parameters"] = parameters send_message = json.dumps( {"type": "iot", "commands": [command]} ) await self.conn.websocket.send(send_message) return raise Exception(f"未找到设备{device_name}的方法{method_name}") def register_iot_tools(self, descriptors: list): """注册IoT工具""" for descriptor in descriptors: device_name = descriptor["name"] device_desc = descriptor["description"] # 注册查询工具 if "properties" in descriptor: for prop_name, prop_info in descriptor["properties"].items(): tool_name = f"get_{device_name.lower()}_{prop_name.lower()}" tool_desc = { "type": "function", "function": { "name": tool_name, "description": f"查询{device_desc}的{prop_info['description']}", "parameters": { "type": "object", "properties": { "response_success": { "type": "string", "description": f"查询成功时的友好回复,必须使用{{value}}作为占位符表示查询到的值", }, "response_failure": { "type": "string", "description": f"查询失败时的友好回复", }, }, "required": ["response_success", "response_failure"], }, }, } self.iot_tools[tool_name] = ToolDefinition( name=tool_name, description=tool_desc, tool_type=ToolType.DEVICE_IOT, ) # 注册控制工具 if "methods" in descriptor: for method_name, method_info in descriptor["methods"].items(): tool_name = f"{device_name.lower()}_{method_name.lower()}" # 构建参数 parameters = {} required_params = [] # 添加方法的原始参数 if "parameters" in method_info: parameters.update( { param_name: { "type": param_info["type"], "description": param_info["description"], } for param_name, param_info in method_info[ "parameters" ].items() } ) required_params.extend(method_info["parameters"].keys()) # 添加响应参数 parameters.update( { "response_success": { "type": "string", "description": "操作成功时的友好回复", }, "response_failure": { "type": "string", "description": "操作失败时的友好回复", }, } ) required_params.extend(["response_success", "response_failure"]) tool_desc = { "type": "function", "function": { "name": tool_name, "description": f"{device_desc} - {method_info['description']}", "parameters": { "type": "object", "properties": parameters, "required": required_params, }, }, } self.iot_tools[tool_name] = ToolDefinition( name=tool_name, description=tool_desc, tool_type=ToolType.DEVICE_IOT, ) def get_tools(self) -> Dict[str, ToolDefinition]: """获取所有设备端IoT工具""" return self.iot_tools.copy() def has_tool(self, tool_name: str) -> bool: """检查是否有指定的设备端IoT工具""" return tool_name in self.iot_tools