mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-28 10:03:54 +08:00
Iot (#126)
* 2025-2-17-iot配置消息处理, 以及控制iot命令发送 (#40) * update:优化 --------- Co-authored-by: Jiao Haoyang <108573524+XuSenfeng@users.noreply.github.com> Co-authored-by: hrz <1710360675@qq.com>
This commit is contained in:
@@ -72,6 +72,9 @@ class ConnectionHandler:
|
|||||||
self.tts_start_speak_time = None
|
self.tts_start_speak_time = None
|
||||||
self.tts_duration = 0
|
self.tts_duration = 0
|
||||||
|
|
||||||
|
# iot相关变量
|
||||||
|
self.iot_descriptors = {}
|
||||||
|
|
||||||
self.cmd_exit = self.config["CMD_exit"]
|
self.cmd_exit = self.config["CMD_exit"]
|
||||||
self.max_cmd_length = 0
|
self.max_cmd_length = 0
|
||||||
for cmd in self.cmd_exit:
|
for cmd in self.cmd_exit:
|
||||||
|
|||||||
@@ -163,5 +163,5 @@ async def no_voice_close_connect(conn):
|
|||||||
if no_voice_time > 1000 * close_connection_no_voice_time:
|
if no_voice_time > 1000 * close_connection_no_voice_time:
|
||||||
conn.client_abort = False
|
conn.client_abort = False
|
||||||
conn.asr_server_receive = False
|
conn.asr_server_receive = False
|
||||||
prompt = "时间过得真快,我都好久没说话了。请你用十个字左右话跟我告别,以“再见”或“拜拜拜”为结尾"
|
prompt = "时间过得真快,我都好久没说话了。请你用十个字左右话跟我告别,以“再见”或“拜拜”为结尾"
|
||||||
await startToChat(conn, prompt)
|
await startToChat(conn, prompt)
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
import json
|
||||||
|
from config.logger import setup_logging
|
||||||
|
|
||||||
|
TAG = __name__
|
||||||
|
logger = setup_logging()
|
||||||
|
|
||||||
|
|
||||||
|
class IotDescriptor:
|
||||||
|
"""
|
||||||
|
A class to represent an IoT descriptor.
|
||||||
|
Attributes:
|
||||||
|
----------
|
||||||
|
name : str
|
||||||
|
The name of the IoT descriptor.
|
||||||
|
description : str
|
||||||
|
A brief description of the IoT descriptor.
|
||||||
|
properties : dict
|
||||||
|
A dictionary containing properties of the IoT descriptor.
|
||||||
|
methods : dict
|
||||||
|
A dictionary containing methods of the IoT descriptor.
|
||||||
|
-------
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, name, description, properties, methods):
|
||||||
|
self.name = name
|
||||||
|
self.description = description
|
||||||
|
self.properties = []
|
||||||
|
self.methods = []
|
||||||
|
|
||||||
|
# 根据描述创建属性
|
||||||
|
for key, value in properties.items():
|
||||||
|
# "volume":{"description":"当前音量 值","type":"number"}
|
||||||
|
"""
|
||||||
|
等价于
|
||||||
|
{
|
||||||
|
'name': 名字,
|
||||||
|
'description': 描述,
|
||||||
|
'value': 0
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
# setattr(self, key, {}) # 创建一个空字典, 名字是属性名
|
||||||
|
property_item = globals()[key] = {} # 创建一个空字典, 名字是属性名
|
||||||
|
property_item['name'] = key
|
||||||
|
property_item["description"] = value["description"]
|
||||||
|
if value["type"] == "number":
|
||||||
|
property_item["value"] = 0
|
||||||
|
elif value["type"] == "bool":
|
||||||
|
property_item["value"] = False
|
||||||
|
elif value["type"] == "string":
|
||||||
|
property_item["value"] = ""
|
||||||
|
else:
|
||||||
|
raise ValueError("Invalid type")
|
||||||
|
self.properties.append(property_item)
|
||||||
|
|
||||||
|
# 根据描述创建方法
|
||||||
|
for key, value in methods.items():
|
||||||
|
# "SetVolume": {"description":"设置音量","parameters":{"volume":{"description":"0到100之间的整数","type":"number"}}}
|
||||||
|
"""
|
||||||
|
等价于
|
||||||
|
SetVolume = {
|
||||||
|
`description`: 描述,
|
||||||
|
`volume`: {
|
||||||
|
`description`: 描述,
|
||||||
|
`value`: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
# setattr(self, key, {}) # 创建一个空字典, 名字是方法名
|
||||||
|
method = globals()[key] = {} # 创建一个空字典, 名字是方法名
|
||||||
|
method["description"] = value["description"]
|
||||||
|
method['name'] = key
|
||||||
|
for k, v in value["parameters"].items():
|
||||||
|
# 不同的参数解析
|
||||||
|
method[k] = {}
|
||||||
|
method[k]["description"] = v["description"]
|
||||||
|
if v["type"] == "number":
|
||||||
|
method[k]["value"] = 0
|
||||||
|
elif v["type"] == "bool":
|
||||||
|
method[k]["value"] = False
|
||||||
|
elif v["type"] == "string":
|
||||||
|
method[k]["value"] = ""
|
||||||
|
else:
|
||||||
|
raise ValueError("Invalid type")
|
||||||
|
|
||||||
|
self.methods.append(method)
|
||||||
|
|
||||||
|
|
||||||
|
async def handleIotDescriptors(conn, descriptors):
|
||||||
|
"""
|
||||||
|
处理物联网描述
|
||||||
|
示例: [{
|
||||||
|
"name":"Speaker",
|
||||||
|
"description":"当前 AI 机器人的扬声器",
|
||||||
|
"properties":{
|
||||||
|
"volume":{"description":"当前音量 值","type":"number"} 可以有bool, int, string三种类型
|
||||||
|
},
|
||||||
|
"methods":{
|
||||||
|
"SetVolume":{
|
||||||
|
"description":"设置音量","parameters":{"volume":{"description":"0到100之间的整数","type":"number"}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
descriptors: 描述列表
|
||||||
|
"""
|
||||||
|
for descriptor in descriptors:
|
||||||
|
iot_descriptor = IotDescriptor(descriptor["name"], descriptor["description"], descriptor["properties"],
|
||||||
|
descriptor["methods"])
|
||||||
|
conn.iot_descriptors[descriptor["name"]] = iot_descriptor
|
||||||
|
|
||||||
|
# 暂时从配置文件中设置音量,后期通过意图识别控制音量
|
||||||
|
default_iot_volume = 100
|
||||||
|
if "iot" in conn.config:
|
||||||
|
default_iot_volume = conn.config["iot"]["Speaker"]["volume"]
|
||||||
|
logger.bind(tag=TAG).info(f"服务端设置音量为{default_iot_volume}")
|
||||||
|
await send_iot_conn(conn, "Speaker", "SetVolume", {"volume": default_iot_volume})
|
||||||
|
|
||||||
|
|
||||||
|
async def send_iot_conn(conn, name, method_name, parameters):
|
||||||
|
"""
|
||||||
|
发送物联网指令
|
||||||
|
name: 设备名称 "Speaker"
|
||||||
|
method: 方法 "SetVolume"
|
||||||
|
parameters: 参数, 是一个字典 {"volume": 100}
|
||||||
|
发送示例:
|
||||||
|
{
|
||||||
|
"type": "iot",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"name" : "Speaker",
|
||||||
|
"method": "SetVolume",
|
||||||
|
"parameters": {
|
||||||
|
"volume": 100
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
for key, value in conn.iot_descriptors.items():
|
||||||
|
if key == name:
|
||||||
|
# 找到了设备
|
||||||
|
for method in value.methods:
|
||||||
|
# 找到了方法
|
||||||
|
if method["name"] == method_name:
|
||||||
|
await conn.websocket.send(json.dumps({
|
||||||
|
"type": "iot",
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"name": name,
|
||||||
|
"method": method_name,
|
||||||
|
"parameters": parameters
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}))
|
||||||
|
return
|
||||||
|
logger.bind(tag=TAG).error(f"未找到方法{method_name}")
|
||||||
@@ -3,6 +3,7 @@ import json
|
|||||||
from core.handle.abortHandle import handleAbortMessage
|
from core.handle.abortHandle import handleAbortMessage
|
||||||
from core.handle.helloHandle import handleHelloMessage
|
from core.handle.helloHandle import handleHelloMessage
|
||||||
from core.handle.audioHandle import startToChat
|
from core.handle.audioHandle import startToChat
|
||||||
|
from core.handle.iotHandle import handleIotDescriptors
|
||||||
|
|
||||||
TAG = __name__
|
TAG = __name__
|
||||||
logger = setup_logging()
|
logger = setup_logging()
|
||||||
@@ -36,5 +37,8 @@ async def handleTextMessage(conn, message):
|
|||||||
conn.asr_audio.clear()
|
conn.asr_audio.clear()
|
||||||
if "text" in msg_json:
|
if "text" in msg_json:
|
||||||
await startToChat(conn, msg_json["text"])
|
await startToChat(conn, msg_json["text"])
|
||||||
|
elif msg_json["type"] == "iot":
|
||||||
|
if "descriptors" in msg_json:
|
||||||
|
await handleIotDescriptors(conn, msg_json["descriptors"])
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
await conn.websocket.send(message)
|
await conn.websocket.send(message)
|
||||||
|
|||||||
Reference in New Issue
Block a user