diff --git a/examples/xiaozhi/.vscode/settings.json b/examples/xiaozhi/.vscode/settings.json new file mode 100644 index 0000000..c139dad --- /dev/null +++ b/examples/xiaozhi/.vscode/settings.json @@ -0,0 +1,23 @@ +{ + "editor.tabSize": 2, + "editor.insertSpaces": true, + "editor.formatOnSave": true, + "python.languageServer": "Pylance", + "python.analysis.autoImportCompletions": true, + "ruff.organizeImports": true, + "[python]": { + "editor.defaultFormatter": "charliermarsh.ruff", + "editor.codeActionsOnSave": { + "source.organizeImports": "explicit", + "source.fixAll": "explicit" + } + }, + "files.exclude": { + "**/.git": true, + "**/node_modules": true, + "**/__pycache__": true, + "*.egg-info": true, + ".venv": true, + ".mypy_cache": true + } +} diff --git a/examples/xiaozhi/Cargo.lock b/examples/xiaozhi/Cargo.lock index 917a777..56cbbcf 100644 --- a/examples/xiaozhi/Cargo.lock +++ b/examples/xiaozhi/Cargo.lock @@ -335,6 +335,7 @@ name = "open-xiaoai" version = "1.0.0" dependencies = [ "futures", + "rand", "serde", "serde_json", "tokio", @@ -519,13 +520,12 @@ checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" [[package]] name = "rand" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha", "rand_core", - "zerocopy", ] [[package]] diff --git a/examples/xiaozhi/config.py b/examples/xiaozhi/config.py new file mode 100644 index 0000000..86c4177 --- /dev/null +++ b/examples/xiaozhi/config.py @@ -0,0 +1,5 @@ +XIAOZHI_CONFIG = { + "OTA_URL": "https://api.tenclass.net/xiaozhi/ota/", + "WEBSOCKET_URL": "wss://api.tenclass.net/xiaozhi/v1/", + "WEBSOCKET_ACCESS_TOKEN": "xxxxxxxxxxxxx", +} diff --git a/examples/xiaozhi/xiaozhi/utils/config_manager.py b/examples/xiaozhi/xiaozhi/utils/config_manager.py index e00b178..f5911ab 100644 --- a/examples/xiaozhi/xiaozhi/utils/config_manager.py +++ b/examples/xiaozhi/xiaozhi/utils/config_manager.py @@ -1,12 +1,10 @@ -import json import logging -import os -from pathlib import Path -from typing import Dict, Any, Optional -import threading -import requests import socket +import threading import uuid +from typing import Any, Optional + +from config import XIAOZHI_CONFIG logger = logging.getLogger("ConfigManager") @@ -16,19 +14,6 @@ class ConfigManager: _instance = None _lock = threading.Lock() - CONFIG_FILE = Path(os.getcwd()) / "xiaozhi.json" - - # 默认配置 - DEFAULT_CONFIG = { - "CLIENT_ID": None, - "DEVICE_ID": None, - "NETWORK": { - "OTA_VERSION_URL": "https://api.tenclass.net/xiaozhi/ota/", - "WEBSOCKET_URL": "wss://api.tenclass.net/xiaozhi/v1/", - "WEBSOCKET_ACCESS_TOKEN": "test-token", - }, - "MQTT_INFO": None, - } def __new__(cls): """确保单例模式""" @@ -44,49 +29,14 @@ class ConfigManager: self._initialized = True # 加载配置 - self._config = self._load_config() + self._config = { + "CLIENT_ID": None, + "DEVICE_ID": None, + "NETWORK": XIAOZHI_CONFIG, + } + self._initialize_client_id() self._initialize_device_id() - self._initialize_mqtt_info() - - def _load_config(self) -> Dict[str, Any]: - """加载配置文件,如果不存在则创建""" - try: - if self.CONFIG_FILE.exists(): - config = json.loads(self.CONFIG_FILE.read_text(encoding="utf-8")) - return self._merge_configs(self.DEFAULT_CONFIG, config) - else: - self._save_config(self.DEFAULT_CONFIG) - return self.DEFAULT_CONFIG.copy() - except Exception as e: - logger.error(f"Error loading config: {e}") - return self.DEFAULT_CONFIG.copy() - - def _save_config(self, config: dict) -> bool: - """保存配置到文件""" - try: - self.CONFIG_FILE.write_text( - json.dumps(config, indent=2, ensure_ascii=False), encoding="utf-8" - ) - return True - except Exception as e: - logger.error(f"Error saving config: {e}") - return False - - @staticmethod - def _merge_configs(default: dict, custom: dict) -> dict: - """递归合并配置字典""" - result = default.copy() - for key, value in custom.items(): - if ( - key in result - and isinstance(result[key], dict) - and isinstance(value, dict) - ): - result[key] = ConfigManager._merge_configs(result[key], value) - else: - result[key] = value - return result def get_client_id(self) -> str: """获取客户端ID""" @@ -122,7 +72,7 @@ class ConfigManager: for part in parts: current = current.setdefault(part, {}) current[last] = value - return self._save_config(self._config) + return True except Exception as e: logger.error(f"Error updating config {path}: {e}") return False @@ -174,83 +124,4 @@ class ConfigManager: logger.error("Failed to save new DEVICE_ID") except Exception as e: logger.error(f"Error generating DEVICE_ID: {e}") - - def _initialize_mqtt_info(self): - try: - mqtt_info = self._get_ota_version() - if mqtt_info: - self.update_config("MQTT_INFO", mqtt_info) - self.logger.info("MQTT信息已成功更新") - return mqtt_info - else: - self.logger.warning("获取MQTT信息失败,使用已保存的配置") - return self.get_config("MQTT_INFO") - - except Exception as e: - self.logger.error(f"初始化MQTT信息失败: {e}") - return self.get_config("MQTT_INFO") - - def _get_ota_version(self): - """获取OTA服务器的MQTT信息""" - MAC_ADDR = self.get_device_id() - OTA_VERSION_URL = self.get_config("NETWORK.OTA_VERSION_URL") - headers = {"Device-Id": MAC_ADDR, "Content-Type": "application/json"} - - # 构建设备信息payload - payload = { - "flash_size": 16777216, # 闪存大小 (16MB) - "minimum_free_heap_size": 8318916, # 最小可用堆内存 - "mac_address": MAC_ADDR, # 设备MAC地址 - "chip_model_name": "esp32s3", # 芯片型号 - "chip_info": {"model": 9, "cores": 2, "revision": 2, "features": 18}, - "application": { - "name": "xiaozhi", - "version": "1.1.2", - "idf_version": "v5.3.2-dirty", - }, - "partition_table": [], - "ota": {"label": "factory"}, - "board": { - "type": "bread-compact-wifi", - "ip": self.get_local_ip(), - "mac": MAC_ADDR, - }, - } - - try: - # 发送请求到OTA服务器 - response = requests.post( - OTA_VERSION_URL, - headers=headers, - json=payload, - timeout=10, - ) - - # 检查HTTP状态码 - if response.status_code != 200: - self.logger.error(f"OTA服务器错误: HTTP {response.status_code}") - raise ValueError(f"OTA服务器返回错误状态码: {response.status_code}") - - # 解析JSON数据 - response_data = response.json() - - # 调试信息:打印完整的OTA响应 - self.logger.debug( - f"OTA服务器返回数据: {json.dumps(response_data, indent=4, ensure_ascii=False)}" - ) - - # 确保"mqtt"信息存在 - if "mqtt" in response_data: - self.logger.info(f"MQTT服务器信息已更新") - return response_data["mqtt"] - else: - self.logger.error("OTA服务器返回的数据无效: MQTT信息缺失") - raise ValueError("OTA服务器返回的数据无效,请检查服务器状态或MAC地址!") - - except requests.Timeout: - self.logger.error("OTA请求超时,请检查网络或服务器状态") - raise ValueError("OTA请求超时!请稍后重试。") - - except requests.RequestException as e: - self.logger.error(f"OTA请求失败: {e}") - raise ValueError("无法连接到OTA服务器,请检查网络连接!") + logger.error(f"Error generating DEVICE_ID: {e}")