wangzhibo
2026-10-08 220e4fab27b7f419b3e89e2f2d28ae789aac09d7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
"""设备端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