xiaozhi-sdk 0.0.2__tar.gz → 0.0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of xiaozhi-sdk might be problematic. Click here for more details.
- {xiaozhi_sdk-0.0.2/xiaozhi_sdk.egg-info → xiaozhi_sdk-0.0.3}/PKG-INFO +7 -4
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/README.md +6 -3
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/setup.py +12 -1
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/tests/test_iot.py +2 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/xiaozhi_sdk/__init__.py +36 -17
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/xiaozhi_sdk/__main__.py +22 -11
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/xiaozhi_sdk/data.py +1 -1
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/xiaozhi_sdk/iot.py +5 -9
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/xiaozhi_sdk/mcp.py +8 -6
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3/xiaozhi_sdk.egg-info}/PKG-INFO +7 -4
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/LICENSE +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/MANIFEST.in +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/file/audio/greet.wav +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/file/audio/say_hello.wav +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/file/audio/take_photo.wav +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/file/image/leijun.jpg +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/file/opus/linux-arm64-libopus.so +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/file/opus/linux-x64-libopus.so +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/file/opus/macos-arm64-libopus.dylib +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/file/opus/macos-x64-libopus.dylib +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/file/opus/windows-x86_64-opus.dll +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/setup.cfg +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/tests/test_opus.py +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/tests/test_pic.py +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/tests/test_xiaozhi.py +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/xiaozhi_sdk/config.py +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/xiaozhi_sdk/opus.py +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/xiaozhi_sdk/utils.py +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/xiaozhi_sdk.egg-info/SOURCES.txt +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/xiaozhi_sdk.egg-info/dependency_links.txt +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/xiaozhi_sdk.egg-info/requires.txt +0 -0
- {xiaozhi_sdk-0.0.2 → xiaozhi_sdk-0.0.3}/xiaozhi_sdk.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xiaozhi-sdk
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.3
|
|
4
4
|
Summary: 一个用于连接和控制小智智能设备的Python SDK,支持实时音频通信、MCP工具集成和设备管理功能。
|
|
5
5
|
Home-page: https://github.com/dairoot/xiaozhi-sdk
|
|
6
6
|
Author: dairoot
|
|
@@ -71,9 +71,12 @@ positional arguments:
|
|
|
71
71
|
device 你的小智设备的MAC地址 (格式: XX:XX:XX:XX:XX:XX)
|
|
72
72
|
|
|
73
73
|
options:
|
|
74
|
-
-h, --help
|
|
75
|
-
--url URL
|
|
76
|
-
--ota_url OTA_URL
|
|
74
|
+
-h, --help show this help message and exit
|
|
75
|
+
--url URL 服务端websocket地址
|
|
76
|
+
--ota_url OTA_URL OTA地址
|
|
77
|
+
--serial_number SERIAL_NUMBER 设备的序列号
|
|
78
|
+
--license_key LICENSE_KEY 设备的授权密钥
|
|
79
|
+
|
|
77
80
|
```
|
|
78
81
|
|
|
79
82
|
#### 连接设备(需要提供 MAC 地址)
|
|
@@ -39,9 +39,12 @@ positional arguments:
|
|
|
39
39
|
device 你的小智设备的MAC地址 (格式: XX:XX:XX:XX:XX:XX)
|
|
40
40
|
|
|
41
41
|
options:
|
|
42
|
-
-h, --help
|
|
43
|
-
--url URL
|
|
44
|
-
--ota_url OTA_URL
|
|
42
|
+
-h, --help show this help message and exit
|
|
43
|
+
--url URL 服务端websocket地址
|
|
44
|
+
--ota_url OTA_URL OTA地址
|
|
45
|
+
--serial_number SERIAL_NUMBER 设备的序列号
|
|
46
|
+
--license_key LICENSE_KEY 设备的授权密钥
|
|
47
|
+
|
|
45
48
|
```
|
|
46
49
|
|
|
47
50
|
#### 连接设备(需要提供 MAC 地址)
|
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import re
|
|
2
3
|
|
|
3
4
|
from setuptools import find_packages, setup
|
|
4
5
|
|
|
5
6
|
|
|
7
|
+
# 读取版本号
|
|
8
|
+
def get_version():
|
|
9
|
+
with open(os.path.join("xiaozhi_sdk", "__init__.py"), "r", encoding="utf-8") as f:
|
|
10
|
+
content = f.read()
|
|
11
|
+
match = re.search(r'^__version__ = [\'"]([^\'"]*)[\'"]', content, re.M)
|
|
12
|
+
if match:
|
|
13
|
+
return match.group(1)
|
|
14
|
+
raise RuntimeError("Unable to find version string.")
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
# 收集指定目录下的所有文件
|
|
7
18
|
def get_data_files(*directories):
|
|
8
19
|
data_files = []
|
|
@@ -18,7 +29,7 @@ def get_data_files(*directories):
|
|
|
18
29
|
|
|
19
30
|
setup(
|
|
20
31
|
name="xiaozhi-sdk", # 包名
|
|
21
|
-
version=
|
|
32
|
+
version=get_version(), # 版本号
|
|
22
33
|
packages=find_packages(), # 自动发现包
|
|
23
34
|
package_data={
|
|
24
35
|
"xiaozhi_sdk": ["../" + f for f in get_data_files("file")], # 包含file目录下的所有文件
|
|
@@ -16,4 +16,6 @@ async def test_main():
|
|
|
16
16
|
mac_address = "00:22:44:66:88:00"
|
|
17
17
|
ota = OtaDevice(mac_addr=mac_address, client_id=str(uuid.uuid4()), serial_number=serial_number)
|
|
18
18
|
res = await ota.activate_device()
|
|
19
|
+
if not res.get("activation"):
|
|
20
|
+
return
|
|
19
21
|
await ota.check_activate(res["activation"]["challenge"], license_key)
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
__version__ = "0.0.3"
|
|
2
|
+
|
|
1
3
|
import asyncio
|
|
2
4
|
import json
|
|
5
|
+
import logging
|
|
3
6
|
import os
|
|
4
7
|
import re
|
|
5
8
|
import uuid
|
|
@@ -16,6 +19,8 @@ from xiaozhi_sdk.utils import get_wav_info, read_audio_file, setup_opus
|
|
|
16
19
|
setup_opus()
|
|
17
20
|
from xiaozhi_sdk.opus import AudioOpus
|
|
18
21
|
|
|
22
|
+
logger = logging.getLogger("xiaozhi_sdk")
|
|
23
|
+
|
|
19
24
|
|
|
20
25
|
class XiaoZhiWebsocket(McpTool):
|
|
21
26
|
|
|
@@ -75,7 +80,7 @@ class XiaoZhiWebsocket(McpTool):
|
|
|
75
80
|
listen_message = {"session_id": self.session_id, "type": "listen", "state": "start", "mode": "realtime"}
|
|
76
81
|
await self.websocket.send(json.dumps(listen_message))
|
|
77
82
|
|
|
78
|
-
async def _activate_iot_device(self, ota_info: Dict[str, Any]) -> None:
|
|
83
|
+
async def _activate_iot_device(self, license_key: str, ota_info: Dict[str, Any]) -> None:
|
|
79
84
|
"""激活IoT设备"""
|
|
80
85
|
if not ota_info.get("activation"):
|
|
81
86
|
return
|
|
@@ -88,7 +93,7 @@ class XiaoZhiWebsocket(McpTool):
|
|
|
88
93
|
await asyncio.sleep(3)
|
|
89
94
|
|
|
90
95
|
for _ in range(10):
|
|
91
|
-
if await self.ota.check_activate(challenge):
|
|
96
|
+
if await self.ota.check_activate(challenge, license_key):
|
|
92
97
|
break
|
|
93
98
|
await asyncio.sleep(3)
|
|
94
99
|
|
|
@@ -114,20 +119,23 @@ class XiaoZhiWebsocket(McpTool):
|
|
|
114
119
|
|
|
115
120
|
async def _handle_websocket_message(self, message: Any) -> None:
|
|
116
121
|
"""处理接受到的WebSocket消息"""
|
|
122
|
+
|
|
123
|
+
# audio data
|
|
117
124
|
if isinstance(message, bytes):
|
|
118
125
|
pcm_array = await self.audio_opus.opus_to_pcm(message)
|
|
119
126
|
self.output_audio_queue.extend(pcm_array)
|
|
120
|
-
|
|
121
|
-
data = json.loads(message)
|
|
122
|
-
message_type = data["type"]
|
|
127
|
+
return
|
|
123
128
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
# json message
|
|
130
|
+
data = json.loads(message)
|
|
131
|
+
message_type = data["type"]
|
|
132
|
+
if message_type == "hello":
|
|
133
|
+
self.hello_received.set()
|
|
134
|
+
self.session_id = data["session_id"]
|
|
135
|
+
elif message_type == "mcp":
|
|
136
|
+
await self.mcp(data)
|
|
137
|
+
elif self.message_handler_callback:
|
|
138
|
+
await self.message_handler_callback(data)
|
|
131
139
|
|
|
132
140
|
async def _message_handler(self) -> None:
|
|
133
141
|
"""消息处理器"""
|
|
@@ -144,7 +152,9 @@ class XiaoZhiWebsocket(McpTool):
|
|
|
144
152
|
"""设置MCP工具回调函数"""
|
|
145
153
|
self.tool_func = tool_func
|
|
146
154
|
|
|
147
|
-
async def init_connection(
|
|
155
|
+
async def init_connection(
|
|
156
|
+
self, mac_addr: str, aec: bool = False, serial_number: str = "", license_key: str = ""
|
|
157
|
+
) -> None:
|
|
148
158
|
"""初始化连接"""
|
|
149
159
|
# 校验MAC地址格式 XX:XX:XX:XX:XX:XX
|
|
150
160
|
mac_pattern = r"^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$"
|
|
@@ -152,8 +162,14 @@ class XiaoZhiWebsocket(McpTool):
|
|
|
152
162
|
raise ValueError(f"无效的MAC地址格式: {mac_addr}。正确格式应为 XX:XX:XX:XX:XX:XX")
|
|
153
163
|
|
|
154
164
|
self.mac_addr = mac_addr.lower()
|
|
155
|
-
|
|
165
|
+
|
|
166
|
+
self.ota = OtaDevice(self.mac_addr, self.client_id, self.ota_url, serial_number)
|
|
156
167
|
ota_info = await self.ota.activate_device()
|
|
168
|
+
ws_url = ota_info["websocket"]["url"]
|
|
169
|
+
self.url = self.url or ws_url
|
|
170
|
+
|
|
171
|
+
if "tenclass.net" not in self.url and "xiaozhi.me" not in self.url:
|
|
172
|
+
logger.warning("[websocket] 检测到非官方服务器,请谨慎使用!当前链接地址: %s", self.url)
|
|
157
173
|
|
|
158
174
|
headers = {
|
|
159
175
|
"Authorization": "Bearer {}".format(ota_info["websocket"]["token"]),
|
|
@@ -161,13 +177,16 @@ class XiaoZhiWebsocket(McpTool):
|
|
|
161
177
|
"Device-Id": self.mac_addr,
|
|
162
178
|
"Client-Id": self.client_id,
|
|
163
179
|
}
|
|
164
|
-
|
|
165
|
-
|
|
180
|
+
try:
|
|
181
|
+
self.websocket = await websockets.connect(uri=self.url, additional_headers=headers)
|
|
182
|
+
except websockets.exceptions.InvalidMessage as e:
|
|
183
|
+
logger.error("[websocket] 连接失败,请检查网络连接或设备状态。当前链接地址: %s, 错误信息:%s", self.url, e)
|
|
184
|
+
return
|
|
166
185
|
self.message_handler_task = asyncio.create_task(self._message_handler())
|
|
167
186
|
|
|
168
187
|
await self._send_hello(aec)
|
|
169
188
|
await self._start_listen()
|
|
170
|
-
asyncio.create_task(self._activate_iot_device(ota_info))
|
|
189
|
+
asyncio.create_task(self._activate_iot_device(license_key, ota_info))
|
|
171
190
|
await asyncio.sleep(0.5)
|
|
172
191
|
|
|
173
192
|
async def send_audio(self, pcm: bytes) -> None:
|
|
@@ -51,16 +51,22 @@ async def play_assistant_audio(audio_queue: deque[bytes]):
|
|
|
51
51
|
class XiaoZhiClient:
|
|
52
52
|
"""小智客户端类"""
|
|
53
53
|
|
|
54
|
-
def __init__(
|
|
55
|
-
self
|
|
54
|
+
def __init__(
|
|
55
|
+
self,
|
|
56
|
+
url: Optional[str] = None,
|
|
57
|
+
ota_url: Optional[str] = None,
|
|
58
|
+
):
|
|
56
59
|
self.xiaozhi: Optional[XiaoZhiWebsocket] = None
|
|
57
60
|
self.url = url
|
|
58
61
|
self.ota_url = ota_url
|
|
59
62
|
|
|
60
|
-
async def start(self):
|
|
63
|
+
async def start(self, mac_address: str, serial_number: str = "", license_key: str = ""):
|
|
61
64
|
"""启动客户端连接"""
|
|
65
|
+
self.mac_address = mac_address
|
|
62
66
|
self.xiaozhi = XiaoZhiWebsocket(handle_message, url=self.url, ota_url=self.ota_url)
|
|
63
|
-
await self.xiaozhi.init_connection(
|
|
67
|
+
await self.xiaozhi.init_connection(
|
|
68
|
+
self.mac_address, aec=False, serial_number=serial_number, license_key=license_key
|
|
69
|
+
)
|
|
64
70
|
asyncio.create_task(play_assistant_audio(self.xiaozhi.output_audio_queue))
|
|
65
71
|
|
|
66
72
|
def audio_callback(self, indata, frames, time, status):
|
|
@@ -83,19 +89,24 @@ class XiaoZhiClient:
|
|
|
83
89
|
async def main():
|
|
84
90
|
"""主函数"""
|
|
85
91
|
parser = argparse.ArgumentParser(description="小智SDK客户端")
|
|
86
|
-
parser.add_argument("device", help="
|
|
87
|
-
parser.add_argument("--url", help="
|
|
88
|
-
parser.add_argument("--ota_url", help="
|
|
92
|
+
parser.add_argument("device", help="设备的MAC地址 (格式: XX:XX:XX:XX:XX:XX)")
|
|
93
|
+
parser.add_argument("--url", help="服务端websocket地址")
|
|
94
|
+
parser.add_argument("--ota_url", help="OTA地址")
|
|
95
|
+
|
|
96
|
+
parser.add_argument("--serial_number", default="", help="设备的序列号")
|
|
97
|
+
parser.add_argument("--license_key", default="", help="设备的授权密钥")
|
|
89
98
|
|
|
90
99
|
args = parser.parse_args()
|
|
91
100
|
logger.info("Recording... Press Ctrl+C to stop.")
|
|
92
|
-
|
|
93
|
-
client
|
|
94
|
-
await client.start()
|
|
101
|
+
client = XiaoZhiClient(args.url, args.ota_url)
|
|
102
|
+
await client.start(args.device, args.serial_number, args.license_key)
|
|
95
103
|
|
|
96
104
|
with sd.InputStream(callback=client.audio_callback, channels=1, samplerate=16000, blocksize=960):
|
|
97
105
|
await client.process_audio_input()
|
|
98
106
|
|
|
99
107
|
|
|
100
108
|
if __name__ == "__main__":
|
|
101
|
-
|
|
109
|
+
try:
|
|
110
|
+
asyncio.run(main())
|
|
111
|
+
except KeyboardInterrupt:
|
|
112
|
+
logger.info("Stopping...")
|
|
@@ -16,7 +16,7 @@ mcp_tool_conf: Dict[str, Dict[str, Any]] = {
|
|
|
16
16
|
"inputSchema": {"type": "object", "properties": {}},
|
|
17
17
|
},
|
|
18
18
|
"set_volume": {
|
|
19
|
-
"description": "Set the volume of the audio speaker. If the current volume is unknown, you must call `
|
|
19
|
+
"description": "Set the volume of the audio speaker. If the current volume is unknown, you must call `get_device_status` tool first and then call this tool.",
|
|
20
20
|
"inputSchema": {
|
|
21
21
|
"type": "object",
|
|
22
22
|
"properties": {"volume": {"type": "integer", "minimum": 0, "maximum": 100}},
|
|
@@ -5,13 +5,13 @@ from typing import Any, Dict, Optional
|
|
|
5
5
|
|
|
6
6
|
import aiohttp
|
|
7
7
|
|
|
8
|
+
from xiaozhi_sdk import __version__
|
|
8
9
|
from xiaozhi_sdk.config import OTA_URL
|
|
9
10
|
|
|
10
11
|
# 常量定义
|
|
11
|
-
DEFAULT_APPLICATION_VERSION = "1.0.0"
|
|
12
12
|
BOARD_TYPE = "xiaozhi-sdk-box"
|
|
13
|
-
USER_AGENT = "xiaozhi-sdk/{}".format(
|
|
14
|
-
BOARD_NAME = "xiaozhi-sdk-{}".format(
|
|
13
|
+
USER_AGENT = "xiaozhi-sdk/{}".format(__version__)
|
|
14
|
+
BOARD_NAME = "xiaozhi-sdk-{}".format(__version__)
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class OtaDevice:
|
|
@@ -46,7 +46,7 @@ class OtaDevice:
|
|
|
46
46
|
headers["serial-number"] = self.serial_number
|
|
47
47
|
|
|
48
48
|
payload = {
|
|
49
|
-
"application": {"version":
|
|
49
|
+
"application": {"version": __version__},
|
|
50
50
|
"board": {
|
|
51
51
|
"type": BOARD_TYPE,
|
|
52
52
|
"name": BOARD_NAME,
|
|
@@ -65,11 +65,7 @@ class OtaDevice:
|
|
|
65
65
|
hmac_instance = hmac.new(license_key.encode(), challenge.encode(), hashlib.sha256)
|
|
66
66
|
hmac_result = hmac_instance.hexdigest()
|
|
67
67
|
|
|
68
|
-
payload = {
|
|
69
|
-
"serial_number": self.serial_number,
|
|
70
|
-
"challenge": challenge,
|
|
71
|
-
"hmac": hmac_result
|
|
72
|
-
}
|
|
68
|
+
payload = {"serial_number": self.serial_number, "challenge": challenge, "hmac": hmac_result}
|
|
73
69
|
|
|
74
70
|
async with aiohttp.ClientSession() as session:
|
|
75
71
|
async with session.post(url, headers=headers, data=json.dumps(payload)) as response:
|
|
@@ -51,7 +51,7 @@ class McpTool(object):
|
|
|
51
51
|
try:
|
|
52
52
|
tool_res, is_error = tool_func(mcp_json["params"]["arguments"])
|
|
53
53
|
except Exception as e:
|
|
54
|
-
logger.error("tool_func error: %s", e)
|
|
54
|
+
logger.error("[MCP] tool_func error: %s", e)
|
|
55
55
|
return
|
|
56
56
|
|
|
57
57
|
if tool_name == "take_photo":
|
|
@@ -76,7 +76,7 @@ class McpTool(object):
|
|
|
76
76
|
pass
|
|
77
77
|
|
|
78
78
|
elif method == "notifications/cancelled":
|
|
79
|
-
logger.error("MCP 工具加载失败")
|
|
79
|
+
logger.error("[MCP] 工具加载失败")
|
|
80
80
|
|
|
81
81
|
elif method == "tools/list":
|
|
82
82
|
mcp_tools_payload["id"] = payload["id"]
|
|
@@ -87,14 +87,16 @@ class McpTool(object):
|
|
|
87
87
|
mcp_tool_conf[name]["name"] = name
|
|
88
88
|
mcp_tools_payload["result"]["tools"].append(mcp_tool_conf[name])
|
|
89
89
|
await self.websocket.send(self.get_mcp_json(mcp_tools_payload))
|
|
90
|
-
|
|
91
|
-
logger.info("MCP 加载成功,当前可用工具列表为:%s", tool_list)
|
|
90
|
+
logger.info("[MCP] 加载成功,当前可用工具列表为:%s", tool_list)
|
|
92
91
|
|
|
93
92
|
elif method == "tools/call":
|
|
94
93
|
tool_name = payload["params"]["name"]
|
|
95
94
|
if not self.tool_func.get(tool_name):
|
|
96
|
-
|
|
95
|
+
logger.warning("[MCP] Tool not found: %s", tool_name)
|
|
96
|
+
return
|
|
97
|
+
|
|
97
98
|
mcp_res = await self.mcp_tool_call(payload)
|
|
98
99
|
await self.websocket.send(mcp_res)
|
|
100
|
+
logger.info("[MCP] Tool %s called", tool_name)
|
|
99
101
|
else:
|
|
100
|
-
logger.warning("unknown method %s: %s", method, payload)
|
|
102
|
+
logger.warning("[MCP] unknown method %s: %s", method, payload)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xiaozhi-sdk
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.3
|
|
4
4
|
Summary: 一个用于连接和控制小智智能设备的Python SDK,支持实时音频通信、MCP工具集成和设备管理功能。
|
|
5
5
|
Home-page: https://github.com/dairoot/xiaozhi-sdk
|
|
6
6
|
Author: dairoot
|
|
@@ -71,9 +71,12 @@ positional arguments:
|
|
|
71
71
|
device 你的小智设备的MAC地址 (格式: XX:XX:XX:XX:XX:XX)
|
|
72
72
|
|
|
73
73
|
options:
|
|
74
|
-
-h, --help
|
|
75
|
-
--url URL
|
|
76
|
-
--ota_url OTA_URL
|
|
74
|
+
-h, --help show this help message and exit
|
|
75
|
+
--url URL 服务端websocket地址
|
|
76
|
+
--ota_url OTA_URL OTA地址
|
|
77
|
+
--serial_number SERIAL_NUMBER 设备的序列号
|
|
78
|
+
--license_key LICENSE_KEY 设备的授权密钥
|
|
79
|
+
|
|
77
80
|
```
|
|
78
81
|
|
|
79
82
|
#### 连接设备(需要提供 MAC 地址)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|