VWED_server/VWED任务模块接口文档/WebSocket接口文档.md

19 KiB
Raw Blame History

VWED WebSocket接口文档

本文档描述了VWED系统WebSocket相关的API接口主要用于实时推送任务执行结果和状态更新。

基础信息

  • 基础路径:/ws
  • 接口标签:WebSocket
  • 协议WebSocket协议ws://或wss://

接口清单

序号 接口名称 接口路径 协议 接口描述
1 任务执行结果实时推送 /task-execution/{task_record_id} WebSocket 实时推送指定任务记录的执行结果更新
2 任务执行结果广播 /task-execution-broadcast/{task_record_id} WebSocket 接收任务执行结果广播消息
3 库位状态实时推送 /storage-location/{scene_id} WebSocket 实时推送指定场景的库位状态更新
4 库位状态广播 /storage-location-broadcast/{scene_id} WebSocket 接收库位状态广播消息

接口详情

1. 任务执行结果实时推送

接口说明

建立WebSocket连接实时接收指定任务记录的执行结果更新。服务器会定期推送任务状态变化客户端也可以主动请求获取当前状态。

连接路径

ws://your-domain/ws/task-execution/{task_record_id}?interval={interval}

路径参数

参数名 类型 是否必须 描述
task_record_id string 任务记录ID

查询参数

参数名 类型 是否必须 默认值 描述
interval integer 2 推送间隔范围1-30秒

客户端消息格式

客户端可以向服务器发送以下格式的JSON消息

心跳检测
{
    "type": "ping",
    "timestamp": "2025-06-11T12:00:00.000Z"
}
获取当前状态
{
    "type": "get_status",
    "timestamp": "2025-06-11T12:00:00.000Z"
}

服务器消息格式

任务执行结果更新
{
    "type": "task_execution_update",
    "task_record_id": "任务记录ID",
    "timestamp": "2025-06-11T12:00:00.000Z",
    "message": "成功获取任务记录执行结果",
    "data": [
        {
            "created_at": "2025-06-11T12:00:00.000Z",
            "context": "[块执行名称] 执行内容描述",
            "status": "SUCCESS/FAILED/RUNNING"
        }
    ]
}
心跳响应
{
    "type": "pong",
    "timestamp": "2025-06-11T12:00:00.000Z"
}
错误消息
{
    "type": "error",
    "task_record_id": "任务记录ID",
    "timestamp": "2025-06-11T12:00:00.000Z",
    "message": "错误描述信息"
}

响应字段说明

任务执行结果字段
字段名 类型 描述
type string 消息类型,固定为"task_execution_update"
task_record_id string 任务记录ID
timestamp string 消息时间戳ISO 8601格式
message string 响应消息描述
data array 执行结果数组
data[].created_at string 结果创建时间ISO 8601格式
data[].context string 执行内容描述
data[].status string 执行状态SUCCESS成功、FAILED失败、RUNNING执行中

连接示例

JavaScript客户端示例
// 建立WebSocket连接
const taskRecordId = "your-task-record-id";
const interval = 2; // 推送间隔2秒
const wsUrl = `ws://localhost:8000/ws/task-execution/${taskRecordId}?interval=${interval}`;

const websocket = new WebSocket(wsUrl);

// 连接建立
websocket.onopen = function(event) {
    console.log("WebSocket连接已建立");
    
    // 发送心跳包
    websocket.send(JSON.stringify({
        type: "ping",
        timestamp: new Date().toISOString()
    }));
};

// 接收消息
websocket.onmessage = function(event) {
    const data = JSON.parse(event.data);
    
    switch(data.type) {
        case "task_execution_update":
            console.log("任务执行结果更新:", data.data);
            break;
        case "pong":
            console.log("心跳响应:", data.timestamp);
            break;
        case "error":
            console.error("服务器错误:", data.message);
            break;
    }
};

// 连接关闭
websocket.onclose = function(event) {
    console.log("WebSocket连接已关闭");
};

// 连接错误
websocket.onerror = function(error) {
    console.error("WebSocket连接错误:", error);
};
Python客户端示例
import asyncio
import json
import websockets

async def websocket_client():
    task_record_id = "your-task-record-id"
    interval = 2
    uri = f"ws://localhost:8000/ws/task-execution/{task_record_id}?interval={interval}"
    
    async with websockets.connect(uri) as websocket:
        print("WebSocket连接已建立")
        
        # 发送心跳包
        await websocket.send(json.dumps({
            "type": "ping",
            "timestamp": datetime.now().isoformat()
        }))
        
        # 监听消息
        async for message in websocket:
            data = json.loads(message)
            
            if data["type"] == "task_execution_update":
                print(f"任务执行结果更新: {data['data']}")
            elif data["type"] == "pong":
                print(f"心跳响应: {data['timestamp']}")
            elif data["type"] == "error":
                print(f"服务器错误: {data['message']}")

# 运行客户端
asyncio.run(websocket_client())

特性说明

  1. 智能推送:服务器只在数据发生变化时才推送更新,避免不必要的网络流量
  2. 心跳检测:支持客户端主动发送心跳包,维持连接活跃状态
  3. 错误处理:完善的错误处理机制,连接异常时自动清理资源
  4. 状态查询:客户端可随时主动请求获取当前任务状态
  5. 多客户端支持:同一任务记录可支持多个客户端同时连接

2. 任务执行结果广播

接口说明

建立WebSocket连接接收任务执行结果的广播消息。与实时推送接口的区别在于此接口主要用于被动接收广播不会主动定期推送。

连接路径

ws://your-domain/ws/task-execution-broadcast/{task_record_id}

路径参数

参数名 类型 是否必须 描述
task_record_id string 任务记录ID

客户端消息格式

心跳检测
{
    "type": "ping",
    "timestamp": "2025-06-11T12:00:00.000Z"
}

服务器消息格式

与任务执行结果实时推送接口相同,参见上述文档。

使用场景

  1. 监控面板:多个监控客户端同时监听任务状态变化
  2. 日志收集:收集任务执行过程中的状态变化记录
  3. 事件通知:当任务状态发生变化时接收通知

3. 库位状态实时推送

接口说明

建立WebSocket连接实时接收指定场景的库位状态更新。服务器会定期推送库位状态变化客户端也可以主动请求获取当前状态。支持多种过滤条件来筛选特定的库位。

连接路径

ws://your-domain/ws/storage-location/{scene_id}?interval={interval}&storage_area_id={storage_area_id}&station_name={station_name}&layer_name={layer_name}&is_occupied={is_occupied}&is_locked={is_locked}&is_disabled={is_disabled}

路径参数

参数名 类型 是否必须 描述
scene_id string 场景ID

查询参数

参数名 类型 是否必须 默认值 描述
interval integer 3 推送间隔范围1-30秒
storage_area_id string null 库区ID用于过滤特定库区
station_name string null 站点名称,用于过滤特定站点
layer_name string null 层名称,用于过滤特定层
is_occupied boolean null 是否占用过滤
is_locked boolean null 是否锁定过滤
is_disabled boolean null 是否禁用过滤

客户端消息格式

客户端可以向服务器发送以下格式的JSON消息

心跳检测
{
    "type": "ping",
    "timestamp": "2025-06-11T12:00:00.000Z"
}
获取当前状态
{
    "type": "get_status",
    "timestamp": "2025-06-11T12:00:00.000Z"
}

服务器消息格式

库位状态更新
{
    "type": "storage_location_update",
    "scene_id": "场景ID",
    "timestamp": "2025-06-11T12:00:00.000Z",
    "message": "成功获取库位状态",
    "data": {
        "total": 100,
        "page": 1,
        "page_size": 1000,
        "total_pages": 1,
        "storage_locations": [
            {
                "id": "层ID",
                "layer_index": 1,
                "layer_name": "层名称",
                "operate_point_id": "动作点ID",
                "station_name": "站点名称",
                "storage_location_name": "库位名称",
                "scene_id": "场景ID",
                "storage_area_id": "库区ID",
                "area_name": "库区名称",
                "is_occupied": false,
                "is_locked": false,
                "is_disabled": false,
                "is_empty_tray": false,
                "locked_by": null,
                "goods_content": "",
                "goods_weight": null,
                "goods_volume": null,
                "goods_stored_at": null,
                "goods_retrieved_at": null,
                "last_access_at": "2025-06-11T12:00:00.000Z",
                "max_weight": 5000,
                "max_volume": 1000,
                "layer_height": 100,
                "tags": "",
                "description": null,
                "created_at": "2025-06-11T12:00:00.000Z",
                "updated_at": "2025-06-11T12:00:00.000Z"
            }
        ]
    }
}
库位状态变化通知
{
    "type": "storage_location_status_change",
    "scene_id": "场景ID",
    "layer_name": "层名称",
    "action": "OCCUPY",
    "timestamp": "2025-06-11T12:00:00.000Z",
    "new_status": {
        "id": "层ID",
        "is_occupied": true,
        "is_locked": false,
        "is_disabled": false,
        "is_empty_tray": false,
        "locked_by": null,
        "goods_content": "货物内容",
        "last_access_at": "2025-06-11T12:00:00.000Z",
        "updated_at": "2025-06-11T12:00:00.000Z"
    }
}
心跳响应
{
    "type": "pong",
    "timestamp": "2025-06-11T12:00:00.000Z"
}
错误消息
{
    "type": "error",
    "scene_id": "场景ID",
    "timestamp": "2025-06-11T12:00:00.000Z",
    "message": "错误描述信息"
}

响应字段说明

库位状态字段
字段名 类型 描述
id string 层ID
layer_index integer 层索引(从1开始)
layer_name string 层名称
operate_point_id string 动作点ID
station_name string 站点名称
storage_location_name string 库位名称
scene_id string 场景ID
storage_area_id string 库区ID
area_name string 库区名称
is_occupied boolean 是否占用
is_locked boolean 是否锁定
is_disabled boolean 是否禁用
is_empty_tray boolean 是否空托盘
locked_by string 锁定者
goods_content string 货物内容
goods_weight integer 货物重量(克)
goods_volume integer 货物体积(立方厘米)
goods_stored_at string 货物存放时间
goods_retrieved_at string 货物取出时间
last_access_at string 最后访问时间
max_weight integer 最大承重(克)
max_volume integer 最大体积(立方厘米)
layer_height integer 层高(毫米)
tags string 标签
description string 层描述
created_at string 创建时间
updated_at string 更新时间

连接示例

JavaScript客户端示例
// 建立WebSocket连接
const sceneId = "your-scene-id";
const interval = 3; // 推送间隔3秒
const storageAreaId = "area-001"; // 过滤特定库区
const wsUrl = `ws://localhost:8000/ws/storage-location/${sceneId}?interval=${interval}&storage_area_id=${storageAreaId}&is_occupied=false`;

const websocket = new WebSocket(wsUrl);

// 连接建立
websocket.onopen = function(event) {
    console.log("库位状态WebSocket连接已建立");
    
    // 发送心跳包
    websocket.send(JSON.stringify({
        type: "ping",
        timestamp: new Date().toISOString()
    }));
};

// 接收消息
websocket.onmessage = function(event) {
    const data = JSON.parse(event.data);
    
    switch(data.type) {
        case "storage_location_update":
            console.log("库位状态更新:", data.data);
            // 处理库位状态列表
            data.data.storage_locations.forEach(location => {
                console.log(`层${location.layer_name}: 占用=${location.is_occupied}, 锁定=${location.is_locked}`);
            });
            break;
        case "storage_location_status_change":
            console.log("库位状态变化:", data.layer_name, data.action, data.new_status);
            break;
        case "pong":
            console.log("心跳响应:", data.timestamp);
            break;
        case "error":
            console.error("服务器错误:", data.message);
            break;
    }
};

// 连接关闭
websocket.onclose = function(event) {
    console.log("库位状态WebSocket连接已关闭");
};

// 连接错误
websocket.onerror = function(error) {
    console.error("库位状态WebSocket连接错误:", error);
};
Python客户端示例
import asyncio
import json
import websockets
from datetime import datetime

async def storage_location_websocket_client():
    scene_id = "your-scene-id"
    interval = 3
    storage_area_id = "area-001"
    uri = f"ws://localhost:8000/ws/storage-location/{scene_id}?interval={interval}&storage_area_id={storage_area_id}&is_occupied=false"
    
    async with websockets.connect(uri) as websocket:
        print("库位状态WebSocket连接已建立")
        
        # 发送心跳包
        await websocket.send(json.dumps({
            "type": "ping",
            "timestamp": datetime.now().isoformat()
        }))
        
        # 监听消息
        async for message in websocket:
            data = json.loads(message)
            
            if data["type"] == "storage_location_update":
                print(f"库位状态更新: 共{data['data']['total']}个库位")
                for location in data["data"]["storage_locations"]:
                    print(f"  层{location['layer_name']}: 占用={location['is_occupied']}, 锁定={location['is_locked']}")
            elif data["type"] == "storage_location_status_change":
                print(f"库位状态变化: {data['layer_name']} {data['action']} {data['new_status']}")
            elif data["type"] == "pong":
                print(f"心跳响应: {data['timestamp']}")
            elif data["type"] == "error":
                print(f"服务器错误: {data['message']}")

# 运行客户端
asyncio.run(storage_location_websocket_client())

特性说明

  1. 智能推送:服务器只在数据发生变化时才推送更新,避免不必要的网络流量
  2. 灵活过滤:支持多种过滤条件,可以精确筛选需要监控的库位
  3. 心跳检测:支持客户端主动发送心跳包,维持连接活跃状态
  4. 错误处理:完善的错误处理机制,连接异常时自动清理资源
  5. 状态查询:客户端可随时主动请求获取当前库位状态
  6. 多客户端支持:同一场景可支持多个客户端同时连接

4. 库位状态广播

接口说明

建立WebSocket连接接收库位状态的广播消息。与实时推送接口的区别在于此接口主要用于被动接收广播不会主动定期推送。

连接路径

ws://your-domain/ws/storage-location-broadcast/{scene_id}

路径参数

参数名 类型 是否必须 描述
scene_id string 场景ID

客户端消息格式

心跳检测
{
    "type": "ping",
    "timestamp": "2025-06-11T12:00:00.000Z"
}

服务器消息格式

与库位状态实时推送接口相同,参见上述文档。

使用场景

  1. 监控面板:多个监控客户端同时监听库位状态变化
  2. 库位管理:实时显示库位占用、锁定状态
  3. 货物追踪:监控货物存放和取出过程
  4. 状态统计:收集库位使用率和状态变化统计

错误码说明

错误码 描述 解决方案
1006 连接异常关闭 检查网络连接,重新建立连接
1011 服务器内部错误 检查服务器状态和日志
1013 临时服务不可用 稍后重试连接

最佳实践

1. 连接管理

  • 实现连接断开后的自动重连机制
  • 合理设置推送间隔,避免过于频繁的请求
  • 及时关闭不需要的连接,释放服务器资源

2. 错误处理

  • 监听onerroronclose事件,处理连接异常
  • 实现重连退避策略,避免连接风暴
  • 记录错误日志,便于问题排查

3. 性能优化

  • 使用合适的推送间隔任务执行结果建议2-5秒库位状态建议3-10秒
  • 客户端及时处理接收到的消息,避免消息积压
  • 对于不活跃的任务,考虑降低推送频率
  • 库位状态推送时,合理使用过滤条件,避免获取过多不必要的数据
  • 对于大规模库位监控,考虑按库区分组建立多个连接

4. 安全考虑

  • 在生产环境中使用WSS协议WebSocket Secure
  • 实现适当的身份验证和授权机制
  • 限制连接数量,防止资源滥用
  • 对于库位状态推送,验证客户端是否有权限访问特定场景的库位数据

注意事项

  1. ID有效性确保传入的任务记录ID和场景ID存在且有效
  2. 网络稳定性WebSocket连接对网络质量要求较高不稳定的网络可能导致频繁断连
  3. 浏览器兼容性确保目标浏览器支持WebSocket协议
  4. 资源清理页面关闭或组件销毁时及时关闭WebSocket连接
  5. 消息处理合理处理接收到的消息避免阻塞UI线程
  6. 过滤条件:库位状态推送时,合理设置过滤条件,避免获取过多数据影响性能
  7. 数据更新频率:库位状态数据更新频率可能较高,建议根据实际需求调整推送间隔
  8. 并发连接:避免对同一场景建立过多并发连接,建议复用连接或使用广播接口

更新日志

版本 日期 更新内容
1.0.0 2025-06-11 初始版本,支持任务执行结果实时推送和广播功能
1.1.0 2025-06-11 新增库位状态实时推送和广播功能,支持多种过滤条件和状态变化通知