ESP32小智AI的WebSocket 调试工具的实现,小智AI后台交互过程揭秘(二、技术原理与实现过程详解 )

在开发 ESP32 小智 AI 终端的过程中,开发者经常面临以下挑战:小智服务器与终端之间的协议交互复杂, 消息格式多样(JSON、二进制、JSON-RPC), 握手流程、认证机制、心跳保活等细节不明确, 缺少完整的协议文档和示例。

现在好啦,猫哥分享一款 ESP32小智AI的WebSocket 调试工具,帮你直观的看清整个接入和交互过程。


项目概述

小智 AI 语音助手是一个基于 WebSocket 协议的智能语音交互系统,支持实时语音识别(STT)、语音合成(TTS)和对话功能。在开发和调试过程中,开发者需要一个能够:

  • 实时监控 WebSocket 通信
  • 发送和接收各种协议消息
  • 测试不同的协议场景
  • 记录和分析通信日志

目标

本项目的目标是提供一个工程级的 WebSocket 调试工具,具备以下特性:

完整性 :支持小智协议的所有消息类型

可视化 :提供直观的图形界面

实时性 :实时显示通信状态和消息

可扩展 :易于添加新的协议测试场景

易用性:开箱即用,无需复杂配置

核心价值

  • 开发效率:快速测试和调试协议
  • 问题定位:清晰的日志帮助定位问题
  • 学习工具:帮助理解小智协议
  • 生产辅助:可用于生产环境问题排查

技术原理

WebSocket 通信模型

1. WebSocket 基础

WebSocket 是一种全双工通信协议,建立在 TCP 之上,特点:

  • 持久连接:一次握手,多次通信
  • 双向通信:客户端和服务器可以随时发送消息
  • 低延迟:无需每次请求都建立连接
  • 二进制支持:原生支持文本和二进制数据
2. 小智协议特点

小智协议基于 WebSocket,具有以下特点:

消息类型

  • 文本消息(TEXT):JSON 格式的控制消息
  • 二进制消息(BINARY):Opus 编码的音频数据

协议流程

复制代码
1. 客户端连接 WebSocket
2. 发送 Hello 握手消息(带认证信息)
3. 发送 Listen 开始监听
4. 发送音频数据(二进制)
5. 接收识别结果(JSON)
6. 接收 TTS 音频(二进制)

认证机制

  • 通过 WebSocket Header 传递 Token
  • Header 字段:
    • Authorization: Bearer token
    • Protocol-Version: 协议版本
    • Device-Id: 设备标识
    • Client-Id: 客户端标识

代理转发机制

本工具采用中间代理模式,工作原理:

复制代码
浏览器 ←→ 调试工具后端 ←→ 小智服务器
为什么需要代理?
  1. 跨域问题(CORS)

    • 浏览器直接连接小智服务器可能被 CORS 策略阻止
    • 后端作为中间层可以绕过 CORS 限制
  2. 协议转换

    • 浏览器 WebSocket API 与小智协议可能不完全兼容
    • 后端可以处理协议细节
  3. 日志记录

    • 代理可以记录所有通信
    • 提供完整的抓包日志
  4. 消息增强

    • 添加时间戳
    • 格式化 JSON
    • 分类显示
转发流程

客户端 → 小智服务器

复制代码
1. 浏览器发送消息到调试工具
2. 调试工具记录日志
3. 调试工具转发到小智服务器

小智服务器 → 客户端

复制代码
1. 小智服务器发送消息到调试工具
2. 调试工具记录日志
3. 调试工具转发到浏览器

消息编码与解码

1. JSON 消息

发送

javascript 复制代码
// 前端
const message = {
  action: "send",
  message_type: "text",
  payload: JSON.stringify({
    "type": "hello",
    "device_id": "web-debugger"
  })
};
ws.send(JSON.stringify(message));

接收

python 复制代码
# 后端
data = await client_ws.receive_json()
if data["action"] == "send":
    await server_ws.send(data["payload"])
2. 二进制消息(Opus)

发送

javascript 复制代码
// 前端
const audioData = await file.arrayBuffer();
const base64Data = btoa(String.fromCharCode(...new Uint8Array(audioData)));

const message = {
  action: "send",
  message_type: "binary",
  payload: base64Data
};
ws.send(JSON.stringify(message));

解码

python 复制代码
# 后端
binary_data = base64.b64decode(data["payload"])
await server_ws.send(binary_data)

接收

python 复制代码
# 后端
async for message in server_ws:
    if isinstance(message, bytes):
        # 二进制消息
        base64_data = base64.b64encode(message).decode()
        await client_ws.send_json({
            "type": "message",
            "direction": "recv",
            "opcode": "binary",
            "length": len(message),
            "payload": base64_data
        })

系统架构

整体架构图

复制代码
┌─────────────────────────────────────────────────────────────┐
│                     浏览器(前端)                      │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────┐ │
│  │  index.html  │  │   app.js     │  │style.css │ │
│  └──────────────┘  └──────────────┘  └──────────┘ │
└────────────────────────┬────────────────────────────────────┘
                     │ WebSocket
                     │ ws://localhost:8000/debug
                     ▼
┌─────────────────────────────────────────────────────────────┐
│              调试工具后端(FastAPI)                  │
│  ┌──────────────────────────────────────────────┐        │
│  │  @app.websocket("/debug")                 │        │
│  │  - 接收客户端消息                          │        │
│  │  - 记录日志                              │        │
│  │  - 转发到小智服务器                        │        │
│  │  - 接收小智服务器消息                      │        │
│  │  - 记录日志                              │        │
│  │  - 转发到客户端                          │        │
│  └──────────────────────────────────────────────┘        │
│  ┌──────────────────────────────────────────────┐        │
│  │  PacketLogger                          │        │
│  │  - 日志存储                              │        │
│  │  - 日志查询                              │        │
│  └──────────────────────────────────────────────┘        │
└────────────────────────┬────────────────────────────────────┘
                     │ WebSocket
                     │ ws://xiaozhi-server:8001/ws
                     ▼
┌─────────────────────────────────────────────────────────────┐
│                 小智服务器                             │
│  - Hello 握手                                      │
│  - Listen 监听                                     │
│  - STT 语音识别                                     │
│  - TTS 语音合成                                     │
│  - 对话管理                                        │
└─────────────────────────────────────────────────────────────┘

后端架构

1. FastAPI 应用

核心组件

python 复制代码
app = FastAPI(title="Xiaozhi WebSocket Debugger")

# 中间件
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 静态文件托管
app.mount("/static", StaticFiles(directory=frontend_path), name="static")

# HTTP 路由
@app.get("/")  # 主页
@app.get("/debug-info")  # 调试信息
@app.get("/test-*.html")  # 测试页面

# WebSocket 路由
@app.websocket("/debug")  # 主调试端点
@app.websocket("/test")  # 简单测试端点
2. WebSocket 处理流程
python 复制代码
@app.websocket("/debug")
async def debug_ws(client_ws: WebSocket):
    # 1. 接受连接
    await client_ws.accept()
    
    # 2. 初始化会话
    session_id = str(uuid.uuid4())[:8]
    config = None
    server_ws = None
    
    # 3. 消息循环
    while True:
        # 接收客户端消息
        data = await client_ws.receive_json()
        
        # 处理不同类型的消息
        if data["action"] == "connect":
            # 连接小智服务器
            server_ws = await connect_to_server(config)
            
        elif data["action"] == "send":
            # 转发消息到小智服务器
            await server_ws.send(message)
            
        elif data["action"] == "get_logs":
            # 返回日志
            logs = logger.get_recent(limit)
            await client_ws.send_json({"type": "logs", "logs": logs})
3. 消息转发任务
python 复制代码
async def forward_server_to_client(client_ws, server_ws, session_id):
    """
    从小智服务器转发消息到客户端
    """
    try:
        async for message in server_ws:
            if isinstance(message, bytes):
                # 二进制消息(音频)
                packet = logger.log("recv", "binary", length=len(message))
                await client_ws.send_json({
                    "type": "message",
                    "direction": "recv",
                    "opcode": "binary",
                    "length": len(message),
                    "payload": base64.b64encode(message).decode()
                })
            else:
                # 文本消息(JSON)
                packet = logger.log("recv", "text", payload=message)
                await client_ws.send_json({
                    "type": "message",
                    "direction": "recv",
                    "opcode": "text",
                    "payload": message
                })
    except Exception as e:
        # 错误处理
        packet = logger.log("system", "error", payload=str(e))
        await client_ws.send_json({"type": "log", "packet": packet})
4. 日志记录器
python 复制代码
class PacketLogger:
    def __init__(self):
        self.packets = []
        self.max_packets = 1000
    
    def log(self, direction: str, opcode: str, 
            payload: Optional[str] = None, 
            length: Optional[int] = None):
        """
        记录一个数据包
        
        参数:
            direction: 方向(send/recv/system/error)
            opcode: 操作码(text/binary/connect/error)
            payload: 载荷内容
            length: 二进制数据长度
        """
        packet = {
            "timestamp": datetime.now().strftime("%H:%M:%S.%f")[:-3],
            "direction": direction,
            "opcode": opcode,
            "payload": payload,
            "length": length
        }
        self.packets.append(packet)
        
        # 限制日志数量
        if len(self.packets) > self.max_packets:
            self.packets.pop(0)
        
        return packet
    
    def get_recent(self, limit: int = 100):
        """获取最近的日志"""
        return self.packets[-limit:]

前端架构

1. 组件结构
复制代码
index.html
├── 头部(Header)
│   ├── 标题
│   └── 状态指示器
├── 侧边栏(Sidebar)
│   ├── 连接配置
│   ├── 发送消息
│   ├── 音频发送
│   └── 快速模板
└── 主内容(Main Content)
    └── 抓包日志
2. JavaScript 模块

核心模块

javascript 复制代码
// 1. 连接管理
let ws = null;
let isConnected = false;

function connect() {
  ws = new WebSocket('ws://localhost:8000/debug');
  ws.onopen = handleOpen;
  ws.onmessage = handleMessage;
  ws.onerror = handleError;
  ws.onclose = handleClose;
}

// 2. 状态管理
function updateConnectionStatus(connected) {
  isConnected = connected;
  // 更新 UI
}

// 3. 消息发送
function sendMessage(messageType, payload) {
  const message = {
    action: "send",
    message_type: messageType,
    payload: payload
  };
  ws.send(JSON.stringify(message));
}

// 4. 日志管理
let logs = [];

function addLogEntry(packet) {
  logs.push(packet);
  renderLogs();
}

function renderLogs() {
  // 渲染日志到 UI
}

// 5. 过滤器
let currentFilter = 'all';

function filterLogs(filter) {
  currentFilter = filter;
  renderLogs();
}
3. WebSocket 消息处理
javascript 复制代码
ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  
  switch (data.type) {
    case 'log':
      // 系统日志
      addLogEntry(data.packet);
      
      // 更新连接状态
      if (data.packet.opcode === 'connected') {
        updateConnectionStatus(true);
      } else if (data.packet.opcode === 'error') {
        updateConnectionStatus(false);
      }
      break;
      
    case 'message':
      // 收到消息(从小智服务器)
      addLogEntry({
        timestamp: getCurrentTimestamp(),
        direction: data.direction,
        opcode: data.opcode,
        payload: data.payload,
        length: data.length
      });
      break;
      
    case 'logs':
      // 日志列表
      logs = data.logs;
      renderLogs();
      break;
      
    case 'error':
      // 错误消息
      updateConnectionStatus(false);
      alert('连接错误: ' + data.message);
      break;
  }
};
4. UI 更新机制

实时更新

javascript 复制代码
function renderLogs() {
  const container = document.getElementById('logContainer');
  container.innerHTML = '';
  
  logs.forEach(log => {
    // 根据过滤器显示
    if (currentFilter !== 'all' && 
        getOpcodeClass(log.opcode) !== currentFilter) {
      return;
    }
    
    // 创建日志条目
    const entry = createLogEntry(log);
    container.appendChild(entry);
  });
  
  // 自动滚动到底部
  container.scrollTop = container.scrollHeight;
}

核心功能

1. WebSocket 连接管理

功能描述

提供完整的 WebSocket 连接生命周期管理,包括:

  • 连接建立:建立到调试工具的连接
  • 认证配置:支持 Token、Device ID 等认证信息
  • 状态监控:实时显示连接状态
  • 断线重连:支持手动重连
实现细节

连接流程

javascript 复制代码
function connect() {
  // 1. 创建 WebSocket
  ws = new WebSocket('ws://localhost:8000/debug');
  
  // 2. 设置事件处理器
  ws.onopen = () => {
    console.log('已连接到后端服务');
    
    // 3. 发送连接配置
    ws.send(JSON.stringify({
      action: 'connect',
      config: {
        server_url: serverUrl,
        token: token,
        device_id: deviceId,
        protocol_version: parseInt(protocolVersion)
      }
    }));
  };
  
  ws.onmessage = handleMessage;
  ws.onerror = handleError;
  ws.onclose = handleClose;
}

后端处理

python 复制代码
@app.websocket("/debug")
async def debug_ws(client_ws: WebSocket):
    await client_ws.accept()
    
    while True:
        data = await client_ws.receive_json()
        
        if data["action"] == "connect":
            config = data["config"]
            
            # 构建认证头
            headers = {
                "Authorization": f"Bearer {config.get('token', '')}",
                "Protocol-Version": str(config.get('protocol_version', 1)),
                "Device-Id": config.get('device_id', 'web-debugger'),
                "Client-Id": config.get('client_id', f'debug-{session_id}')
            }
            
            # 连接目标服务器
            server_ws = await websockets.connect(
                config["server_url"],
                extra_headers=headers,
                max_size=None,
                ping_interval=None,
                close_timeout=10
            )
使用场景
  • 开发测试:快速测试连接配置
  • 协议调试:验证握手流程
  • 问题排查:检查连接失败原因

2. 消息收发

功能描述

支持发送和接收两种类型的消息:

  • 文本消息(TEXT):JSON 格式的控制消息
  • 二进制消息(BINARY):Opus 编码的音频数据
实现细节

发送文本消息

javascript 复制代码
function sendTextMessage() {
  const payload = document.getElementById('messagePayload').value;
  
  ws.send(JSON.stringify({
    action: 'send',
    message_type: 'text',
    payload: payload
  }));
  
  // 添加到日志
  addLogEntry({
    timestamp: getCurrentTimestamp(),
    direction: 'send',
    opcode: 'text',
    payload: payload
  });
}

发送二进制消息

javascript 复制代码
function sendBinaryMessage() {
  const base64Data = document.getElementById('binaryPayload').value;
  
  ws.send(JSON.stringify({
    action: 'send',
    message_type: 'binary',
    payload: base64Data
  }));
  
  // 添加到日志
  addLogEntry({
    timestamp: getCurrentTimestamp(),
    direction: 'send',
    opcode: 'binary',
    length: base64Data.length
  });
}

后端转发

python 复制代码
elif data["action"] == "send":
    if not server_ws:
        await client_ws.send_json({
            "type": "error", 
            "message": "Not connected"
        })
        continue
    
    if data["message_type"] == "text":
        await server_ws.send(data["payload"])
        packet = logger.log("send", "text", payload=data["payload"])
        await client_ws.send_json({"type": "log", "packet": packet})
    
    elif data["message_type"] == "binary":
        binary_data = base64.b64decode(data["payload"])
        await server_ws.send(binary_data)
        packet = logger.log("send", "binary", length=len(binary_data))
        await client_ws.send_json({"type": "log", "packet": packet})
使用场景
  • 协议测试:发送各种 JSON 消息
  • 音频发送:发送 Opus 音频数据
  • 命令执行:发送控制命令

3. 协议测试模板

功能描述

提供预定义的协议消息模板,快速测试常见场景:

  • Hello 握手:设备握手协议
  • Listen 监听:开始监听语音
  • JSON-RPC 调用:方法调用
  • 唤醒词:发送唤醒词
实现细节

模板定义

javascript 复制代码
const templates = {
  hello: {
    type: "hello",
    device_id: "web-debugger",
    protocol_version: 1,
    capabilities: ["stt", "tts", "dialog"]
  },
  
  listen: {
    type: "listen",
    enable: true,
    format: "opus",
    sample_rate: 16000
  },
  
  jsonrpc: {
    jsonrpc: "2.0",
    method: "dialog.send",
    params: {
      text: "你好,小智"
    },
    id: 1
  },
  
  wakeup: {
    type: "wakeup",
    word: "小智小智"
  }
};

function applyTemplate(templateName) {
  const template = templates[templateName];
  document.getElementById('messagePayload').value = JSON.stringify(template, null, 2);
}
使用场景
  • 快速测试:一键发送常用协议
  • 协议学习:了解协议格式
  • 场景模拟:模拟真实使用场景

4. 音频功能

功能描述

支持发送音频文件到小智服务器:

  • 文件格式:.opus, .wav, .mp3
  • 自动转换:自动读取并转换为二进制
  • 大小显示:显示文件大小信息
实现细节

文件读取

javascript 复制代码
async function sendAudioFile() {
  const fileInput = document.getElementById('audioFile');
  const file = fileInput.files[0];
  
  if (!file) {
    alert('请选择音频文件');
    return;
  }
  
  // 读取文件
  const arrayBuffer = await file.arrayBuffer();
  const uint8Array = new Uint8Array(arrayBuffer);
  
  // 转换为 Base64
  const base64Data = btoa(String.fromCharCode(...uint8Array));
  
  // 发送
  ws.send(JSON.stringify({
    action: 'send',
    message_type: 'binary',
    payload: base64Data
  }));
  
  // 添加到日志
  addLogEntry({
    timestamp: getCurrentTimestamp(),
    direction: 'send',
    opcode: 'binary',
    length: arrayBuffer.byteLength,
    filename: file.name
  });
}
使用场景
  • 语音测试:发送测试音频
  • TTS 测试:测试语音合成
  • STT 测试:测试语音识别

5. 抓包日志

功能描述

类似 Wireshark 的日志展示功能:

  • 时间戳:精确到毫秒
  • 方向标识:发送/接收/系统/错误
  • 操作码:TEXT/BINARY/CONNECT 等
  • JSON 格式化:自动格式化 JSON
  • 日志过滤:按类型过滤
  • 日志导出:导出为 JSON 文件
实现细节

日志数据结构

javascript 复制代码
{
  timestamp: "12:34:56.789",  // 时间戳
  direction: "send",           // 方向:send/recv/system/error
  opcode: "text",             // 操作码:text/binary/connect/error
  payload: "{...}",           // 载荷内容
  length: 123                // 二进制数据长度
}

日志渲染

javascript 复制代码
function renderLogs() {
  const container = document.getElementById('logContainer');
  container.innerHTML = '';
  
  logs.forEach(log => {
    // 过滤
    if (currentFilter !== 'all' && 
        getOpcodeClass(log.opcode) !== currentFilter) {
      return;
    }
    
    // 创建条目
    const entry = document.createElement('div');
    entry.className = `log-entry ${getDirectionClass(log.direction)} ${getOpcodeClass(log.opcode)}`;
    
    // 时间戳
    const timestamp = document.createElement('span');
    timestamp.className = 'log-timestamp';
    timestamp.textContent = log.timestamp;
    
    // 方向
    const direction = document.createElement('span');
    direction.className = 'log-direction';
    direction.textContent = getDirectionLabel(log.direction);
    
    // 操作码
    const opcode = document.createElement('span');
    opcode.className = 'log-opcode';
    opcode.textContent = log.opcode;
    
    // 载荷
    const payload = document.createElement('pre');
    payload.className = 'log-payload';
    
    if (log.opcode === 'text') {
      // 格式化 JSON
      try {
        const json = JSON.parse(log.payload);
        payload.textContent = JSON.stringify(json, null, 2);
      } catch {
        payload.textContent = log.payload;
      }
    } else if (log.opcode === 'binary') {
      // 显示二进制信息
      payload.textContent = `[Binary Data] Length: ${log.length} bytes`;
    } else {
      payload.textContent = log.payload;
    }
    
    entry.appendChild(timestamp);
    entry.appendChild(direction);
    entry.appendChild(opcode);
    entry.appendChild(payload);
    container.appendChild(entry);
  });
  
  // 滚动到底部
  container.scrollTop = container.scrollHeight;
}

日志导出

javascript 复制代码
function exportLogs() {
  const dataStr = JSON.stringify(logs, null, 2);
  const blob = new Blob([dataStr], { type: 'application/json' });
  const url = URL.createObjectURL(blob);
  
  const a = document.createElement('a');
  a.href = url;
  a.download = `websocket-logs-${Date.now()}.json`;
  a.click();
  
  URL.revokeObjectURL(url);
}
使用场景
  • 问题排查:查看完整的通信日志
  • 协议分析:分析协议交互
  • 性能分析:查看消息时序
  • 报告生成:导出日志用于报告

实现细节

1. 跨域问题解决

问题

浏览器直接连接小智服务器可能遇到 CORS 错误:

复制代码
Access to WebSocket at 'ws://xiaozhi-server:8001/ws' 
from origin 'http://localhost:8000' has been blocked by CORS policy
解决方案

方案 1:后端代理(采用)

通过 FastAPI 后端作为代理,绕过 CORS 限制:

python 复制代码
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

方案 2:静态文件托管

将前端页面托管在 FastAPI 上,避免跨域:

python 复制代码
app.mount("/static", StaticFiles(directory=frontend_path), name="static")

@app.get("/")
async def root():
    return FileResponse(os.path.join(frontend_path, "index.html"))

2. 超时处理

问题

连接目标服务器时可能长时间无响应。

解决方案

使用 asyncio.wait_for 设置超时:

python 复制代码
try:
    server_ws = await asyncio.wait_for(
        websockets.connect(
            config["server_url"],
            extra_headers=headers,
            max_size=None,
            ping_interval=None,
            close_timeout=10
        ),
        timeout=10.0  # 10秒超时
    )
    
    packet = logger.log("system", "connected", payload="WebSocket connected")
    await client_ws.send_json({"type": "log", "packet": packet})
    
except asyncio.TimeoutError:
    packet = logger.log("system", "error", 
        payload="Connection timeout: Target server did not respond within 10 seconds")
    await client_ws.send_json({"type": "log", "packet": packet})
except Exception as e:
    packet = logger.log("system", "error", payload=f"Connection failed: {str(e)}")
    await client_ws.send_json({"type": "log", "packet": packet})

3. 消息接收优化

问题

FastAPI 的 receive() 方法在某些情况下无法正确接收消息。

解决方案

使用 receive_json() 方法直接获取 JSON 对象:

python 复制代码
# 之前(可能有问题)
msg = await client_ws.receive()
if msg["type"] == "text":
    data = json.loads(msg["text"])

# 现在(更可靠)
data = await client_ws.receive_json()

4. 连接状态同步

问题

前端连接状态与实际状态不同步。

解决方案

后端在连接成功/失败时发送状态消息:

python 复制代码
# 连接成功
packet = logger.log("system", "connected", payload="WebSocket connected")
await client_ws.send_json({"type": "log", "packet": packet})

# 连接失败
packet = logger.log("system", "error", payload=f"Connection failed: {str(e)}")
await client_ws.send_json({"type": "log", "packet": packet})

前端根据收到的消息更新状态:

javascript 复制代码
if (data.type === 'log') {
  addLogEntry(data.packet);
  
  if (data.packet.opcode === 'connected') {
    updateConnectionStatus(true);
  } else if (data.packet.opcode === 'error') {
    updateConnectionStatus(false);
  }
}

5. 批处理文件编码

问题

Windows 批处理文件使用 UTF-8 编码时,中文显示为乱码。

解决方案

在批处理文件开头设置代码页:

batch 复制代码
@echo off
chcp 65001 >nul
echo Xiaozhi WebSocket Debugger

或使用英文提示避免编码问题。


技术栈

后端技术栈

技术 版本 用途
Python 3.8+ 主要开发语言
FastAPI Latest Web 框架
WebSockets Latest WebSocket 支持
Uvicorn Latest ASGI 服务器
asyncio 内置 异步编程

前端技术栈

技术 用途
HTML5 页面结构
CSS3 样式和布局
JavaScript (ES6+) 交互逻辑
WebSocket API WebSocket 通信
FileReader API 文件读取

协议栈

协议 用途
WebSocket 底层通信协议
JSON 文本消息格式
Base64 二进制数据编码
Opus 音频编码格式
JSON-RPC 2.0 远程过程调用

使用场景

1. 开发调试

场景:开发小智集成应用时需要测试协议。

使用方法

  1. 启动调试工具
  2. 配置连接参数
  3. 发送测试消息
  4. 查看返回结果
  5. 分析日志

价值

  • 快速验证协议实现
  • 定位通信问题
  • 理解协议细节

2. 协议学习

场景:学习小智协议的交互流程。

使用方法

  1. 使用快速模板发送消息
  2. 观察返回消息
  3. 分析日志时序
  4. 理解协议规则

价值

  • 直观展示协议流程
  • 帮助理解协议
  • 提供参考实现

3. 问题排查

场景:生产环境出现通信问题。

使用方法

  1. 配置生产服务器地址
  2. 复现问题场景
  3. 查看详细日志
  4. 分析错误原因
  5. 导出日志报告

价值

  • 完整的通信日志
  • 清晰的错误信息
  • 便于问题定位

4. 性能测试

场景:测试服务器的性能和稳定性。

使用方法

  1. 发送大量消息
  2. 观察响应时间
  3. 检查连接稳定性
  4. 分析日志统计

价值

  • 评估服务器性能
  • 发现性能瓶颈
  • 优化通信策略

最佳实践

1. 连接配置

推荐配置

javascript 复制代码
{
  server_url: "ws://xiaozhi-server:8001/ws",
  token: "your-bearer-token",
  device_id: "web-debugger",
  protocol_version: 1
}

注意事项

  • 确保服务器地址正确
  • Token 必须有效
  • Device ID 唯一标识设备

2. 消息发送

最佳实践

  • JSON 消息使用格式化输出
  • 二进制消息先测试小数据
  • 音频文件大小适中(<10MB)
  • 使用快速模板提高效率

3. 日志管理

建议

  • 定期导出重要日志
  • 使用过滤器快速定位
  • 关注错误和警告消息
  • 分析消息时序关系

4. 故障排查

排查步骤

  1. 检查连接状态
  2. 查看错误日志
  3. 验证配置参数
  4. 测试网络连接
  5. 联系技术支持

5. 安全建议

安全措施

  • 不要在生产环境暴露调试工具
  • 使用 HTTPS/WSS 加密通信
  • 保护 Token 不泄露
  • 定期更新依赖包

总结

小智 WebSocket 调试工具是一个功能完善、设计精良的工程级调试工具,具有以下特点:

核心优势

完整性 :覆盖小智协议的所有功能

可靠性 :完善的错误处理和超时机制

易用性 :直观的界面和快速模板

可扩展性 :易于添加新功能

专业性:类似 Wireshark 的日志展示

技术亮点

  • 代理架构:解决 CORS 和协议兼容问题
  • 异步处理:高性能的消息转发
  • 实时更新:即时的状态和日志反馈
  • 模块化设计:清晰的代码结构
  • 完整文档:详细的使用说明

适用场景

  • 开发调试
  • 协议学习
  • 问题排查
  • 性能测试
  • 教学演示

未来展望

  • 支持更多协议格式
  • 添加消息录制和回放
  • 提供统计分析功能
  • 支持多会话管理
  • 集成自动化测试

总结

ESP32 小智 AI 终端的开发调试一直是一个复杂且具有挑战性的任务。协议交互不清晰、缺少可视化工具、测试场景受限等问题严重影响了开发效率。

本工具通过提供完整的协议交互可视化平台,解决了这些痛点,为开发者提供了:

  • 直观的协议交互展示
  • 完整的协议支持
  • 灵活的测试工具
  • 强大的日志记录

这些功能显著提升了开发效率,降低了开发门槛,增强了问题排查能力,是 ESP32 小智 AI 终端开发不可或缺的利器!

相关推荐
irpywp2 小时前
构建生产级 AI Agent工作流
人工智能·github
月光有害2 小时前
简单理解深度学习中的多种归一化方法
人工智能·深度学习
艾莉丝努力练剑2 小时前
【Linux信号】Linux进程信号(上):信号产生方式和闹钟
linux·运维·服务器·c++·人工智能·ubuntu·云原生
Bonnie3732 小时前
算力基建入门-AI时代,算力为何是数字底座
人工智能·程序人生·云原生·个人开发
前端摸鱼匠2 小时前
面试题6:因果掩码(Causal Mask)在Decoder中的作用是什么?训练、推理阶段如何使用?
人工智能·ai·语言模型·自然语言处理·面试
这张生成的图像能检测吗2 小时前
(论文速读)ASFRMT:基于对抗的超特征重构元传递网络弱特征增强与谐波传动故障诊断
人工智能·深度学习·计算机视觉·故障诊断
灰子学技术2 小时前
自定义 Host 头访问 HTTPS 服务时的网关处理逻辑
网络·网络协议·http·https
statistican_ABin2 小时前
Python数据分析-宝马全球汽车销售数据分析(可视化分析)
大数据·人工智能·数据分析·汽车·数据可视化
ARM+FPGA+AI工业主板定制专家2 小时前
基于ARM+FPGA+AI的船舶状态智能监测系统(一)总体设计
网络·arm开发·人工智能·机器学习·fpga开发·自动驾驶