# MES PLC Send 项目文档 ## 📋 项目概述 MES PLC Send 是一个基于 Spring Boot 的多设备联合测试系统,支持 PLC 设备管理、设备组配置、多设备任务编排和执行。系统实现了"模板 + 实例"的设计模式,支持一个设备类型模板对应多个设备实例,实现了设备间的协调和数据传递。 **技术栈**: - Spring Boot 2.x - MyBatis-Plus - S7NetPlus(PLC通信) - MySQL - Server-Sent Events (SSE) 实时推送 **服务端口**:10018 ## 🎯 核心功能 ### 1. 设备管理 - 设备配置管理(PLC IP、设备类型、模块名称等) - 设备状态监控(在线/离线/忙碌/错误/维护中) - 支持5种设备类型: - **大车设备** (`LOAD_VEHICLE`):支持多实例协调,自动状态管理,MES任务处理 - **大理片笼** (`LARGE_GLASS`):格子范围配置,逻辑判断 - **卧转立扫码** (`WORKSTATION_SCANNER`):定时扫描,MES数据读取 - **卧转立** (`WORKSTATION_TRANSFER`):30s缓冲判定,批量处理 - **卧式缓存** (`GLASS_STORAGE`):玻璃存储管理(已实现,但当前不使用) ### 2. 设备组管理 - 设备组配置(支持最大并发设备数控制) - 设备组拓扑可视化 - 设备依赖关系管理(优先级、角色、连接顺序) - 设备组任务编排 ### 3. 多设备任务执行 - **串行执行**:按设备连接顺序执行 - **并行执行**:支持多设备并行执行,通过 `max_concurrent_devices` 控制并发数 - **实时监控**:基于 SSE(Server-Sent Events)的实时状态推送 - **错误处理**:自动重试机制,支持指数退避 - **数据传递**:设备间数据共享和状态同步 ### 4. 设备协调服务 - 设备间数据传递机制 - 设备状态同步 - 设备依赖管理 - 多实例协调(如多车协调) ## 🏗️ 架构设计 ### 目录结构 ``` mes-plcSend/ ├── device/ # 设备管理层 │ ├── entity/ # 实体类 │ │ ├── DeviceConfig.java # 设备配置 │ │ ├── DeviceGroupConfig.java # 设备组配置 │ │ ├── DeviceGroupRelation.java # 设备组关系 │ │ ├── DeviceStatus.java # 设备状态 │ │ └── GlassInfo.java # 玻璃信息 │ ├── service/ # 服务层 │ │ ├── DeviceConfigService.java │ │ ├── DeviceGroupConfigService.java │ │ ├── DeviceCoordinationService.java # 设备协调服务 │ │ └── GlassInfoService.java │ └── controller/ # 控制器 │ ├── DeviceConfigController.java │ ├── DeviceGroupController.java │ └── DevicePlcController.java │ ├── interaction/ # 交互逻辑层 │ ├── base/ # 基础接口 │ │ ├── BaseDeviceLogicHandler.java │ │ ├── DeviceInteraction.java │ │ └── InteractionContext.java │ │ │ ├── vehicle/ # 大车设备专用包 │ │ ├── handler/ │ │ │ └── LoadVehicleLogicHandler.java # 共享逻辑处理器 │ │ ├── flow/ │ │ │ └── LoadVehicleInteraction.java │ │ ├── coordination/ │ │ │ ├── VehicleStatusManager.java # 状态管理器 │ │ │ └── VehicleCoordinationService.java # 协调服务 │ │ └── model/ │ │ ├── VehicleStatus.java │ │ ├── VehiclePosition.java │ │ ├── VehicleState.java │ │ ├── VehiclePath.java │ │ └── VehicleTask.java │ │ │ ├── workstation/ # 卧转立设备包 │ │ ├── base/ │ │ │ └── WorkstationBaseHandler.java │ │ ├── config/ │ │ │ └── WorkstationLogicConfig.java │ │ ├── scanner/ │ │ │ └── handler/ │ │ │ └── HorizontalScannerLogicHandler.java │ │ └── transfer/ │ │ └── handler/ │ │ └── HorizontalTransferLogicHandler.java │ │ │ ├── largeglass/ # 大理片笼设备包 │ │ ├── handler/ │ │ │ └── LargeGlassLogicHandler.java │ │ ├── config/ │ │ │ └── LargeGlassConfig.java │ │ └── model/ │ │ └── GridRange.java │ │ │ ├── flow/ # 交互流程(通用) │ │ ├── GlassStorageInteraction.java │ │ └── LargeGlassInteraction.java │ │ │ └── impl/ # 简单设备实现 │ └── GlassStorageLogicHandler.java │ ├── task/ # 任务管理层 │ ├── entity/ │ │ ├── MultiDeviceTask.java # 多设备任务 │ │ └── TaskStepDetail.java # 任务步骤详情 │ ├── service/ │ │ ├── MultiDeviceTaskService.java │ │ ├── TaskExecutionEngine.java # 任务执行引擎 │ │ └── TaskStatusNotificationService.java # SSE推送服务 │ ├── controller/ │ │ ├── MultiDeviceTaskController.java │ │ └── TaskStatusNotificationController.java │ └── model/ │ ├── RetryPolicy.java # 重试策略 │ ├── TaskExecutionContext.java │ └── TaskExecutionResult.java │ ├── service/ # PLC服务层 │ ├── PlcDynamicDataService.java # PLC动态数据服务 │ └── PlcTestWriteService.java │ └── s7/ # S7通信 └── provider/ └── S7SerializerProvider.java ``` ### 核心设计模式 #### 1. 模板 + 实例模式 **设计理念**:一个设备类型模板(共享逻辑)+ 多个设备实例(独立状态) ``` LoadVehicleLogicHandler (共享逻辑处理器) ↓ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ 大车实例1│ │ 大车实例2│ │ 大车实例3│ │ 状态独立 │ │ 状态独立 │ │ 状态独立 │ └─────────┘ └─────────┘ └─────────┘ ``` **优势**: - 共享逻辑:所有实例使用同一个逻辑处理器 - 独立状态:每个实例有独立的运行时状态 - 灵活配置:设备组可以包含任意数量的实例 - 易于扩展:新增实例只需在数据库添加记录 #### 2. 混合分层架构 - **复杂设备**(如大车):独立包,包含协调服务、状态管理等 - **简单设备**(如玻璃存储):放在通用包中 ## 🔧 核心组件说明 ### 1. 大车设备(LoadVehicle) #### 功能特性 - **空闲状态监控**:没有任务时,`plcRequest` 保持为 1 - **MES任务读取**:当 `mesSend=1` 时,读取 MES 参数(玻璃ID、起始位置、目标位置等) - **位置映射**:将 MES 位置编号(如 900、901)映射为实际网格位置(如 100、500) - **时间计算**:根据车辆速度(grids/second)、当前位置、目标位置计算 `gotime` 和 `cartime` - **状态管理**:`state1~6` 状态流转(0→1→2),自动触发 MES 汇报 - **自动协调**:当 `state=1`(上车完成)时,自动将"卧转立"设备的 `plcRequest` 设置为 0 - **出片逻辑**:支持进片和出片任务,根据 `startSlot` 和 `outboundSlotRanges` 自动判断任务类型 #### 配置参数(extraParams.deviceLogic) ```json { "vehicleCapacity": 6, "vehicleSpeed": 1.0, "minRange": 1, "maxRange": 100, "homePosition": 50, "idleMonitorIntervalMs": 1000, "taskMonitorIntervalMs": 1000, "mesConfirmTimeoutMs": 30000, "positionMapping": { "900": 100, "901": 500 }, "outboundSlotRanges": [ {"start": 1000, "end": 2000} ], "gridPositionMapping": { "1000": 80 } } ``` #### 状态流转 ``` IDLE (空闲) → EXECUTING (执行中) → IDLE (空闲) ``` ### 2. 卧转立扫码(HorizontalScanner) #### 功能特性 - **定时扫描**:可配置扫描间隔(默认 10s) - **MES数据读取**:当 `mesSend=1` 时,读取玻璃信息(`mesGlassId`、`mesWidth`、`mesHeight`、`workLine`) - **数据落库**:将玻璃信息保存到 `glass_info` 表 #### 配置参数(extraParams.deviceLogic) ```json { "scanIntervalMs": 10000, "workLine": 1 } ``` ### 3. 卧转立(HorizontalTransfer) #### 功能特性 - **30s缓冲判定**:等待 30s,如果没有下一片玻璃扫码,则认为是最后一片 - **容量判断**:判断能否放下第二片玻璃 - **批量处理**:将多片玻璃组装成批次 - **PLC写入**:写入 `plcGlassId1~6`、`plcGlassCount`、`inPosition`、`plcRequest` #### 配置参数(extraParams.deviceLogic) ```json { "scanIntervalMs": 10000, "bufferTimeoutMs": 30000, "vehicleCapacity": 2, "monitorIntervalMs": 1000, "workLine": "LINE_001", "positionValue": 100 } ``` ### 4. 大理片笼(LargeGlass) #### 功能特性 - **格子范围配置**:支持多行格子配置(如第一行 1~52 格,第二行 53~101 格) - **格子尺寸配置**:每格的长、宽、厚可配置 - **逻辑判断**:用于位置验证和格子管理,不涉及 PLC 写入 #### 配置参数(extraParams.deviceLogic) ```json { "gridRanges": [ {"row": 1, "start": 1, "end": 52}, {"row": 2, "start": 53, "end": 101} ], "gridLength": 2000, "gridWidth": 1500, "gridThickness": 5 } ``` ## 🚀 使用指南 ### 1. 设备配置 #### 创建设备 ```java DeviceConfig device = new DeviceConfig(); device.setDeviceId("DEVICE_001"); device.setDeviceCode("DEV_001"); device.setDeviceName("大车设备1"); device.setDeviceType(DeviceConfig.DeviceType.LOAD_VEHICLE); device.setPlcIp("192.168.1.101"); device.setPlcPort(102); device.setPlcType(DeviceConfig.PlcType.S7_1200); device.setModuleName("DB1"); device.setProjectId(1L); device.setEnabled(true); // 设置逻辑参数 device.setExtraParams(extraParams); deviceConfigService.createDevice(device); ``` #### 配置设备逻辑参数 在 `extraParams.deviceLogic` 中配置设备特定的逻辑参数,如车辆速度、位置映射等。 ### 2. 设备组配置 #### 创建设备组 ```java DeviceGroupConfig group = new DeviceGroupConfig(); group.setGroupCode("GROUP_001"); group.setGroupName("生产线A"); group.setGroupType(1); // 1-生产线,2-测试线,3-辅助设备组 group.setProjectId(1L); group.setStatus(1); // 0-停用,1-启用,3-维护中 group.setMaxConcurrentDevices(3); // 最大并发设备数 group.setHeartbeatInterval(30); group.setCommunicationTimeout(5000); deviceGroupService.createGroup(group); ``` #### 添加设备到设备组 ```java // 添加设备,设置优先级、角色、连接顺序 deviceGroupService.addDevicesToGroup(groupId, deviceIds, priorities, roles, connectionOrders); ``` ### 3. 任务执行 #### 启动多设备任务 ```java MultiDeviceTaskRequest request = new MultiDeviceTaskRequest(); request.setGroupId(groupId); request.setTaskName("测试任务"); request.setProjectId("PROJECT_001"); request.setParameters(taskParameters); MultiDeviceTask task = multiDeviceTaskService.startTask(request); ``` #### API 端点 - `POST /device/task/start` - 启动任务 - `POST /device/task/list` - 查询任务列表 - `GET /device/task/{taskId}` - 查询任务详情 - `GET /device/task/{taskId}/steps` - 查询任务步骤详情 - `POST /device/task/{taskId}/cancel` - 取消任务 #### 实时监控(SSE) 前端通过 SSE 连接实时接收任务状态更新: ```javascript // 监听指定任务 const eventSource = new EventSource('/task/notification/sse?taskId=xxx'); eventSource.addEventListener('taskStatus', (event) => { const data = JSON.parse(event.data); // 处理任务状态更新 }); eventSource.addEventListener('stepUpdate', (event) => { const data = JSON.parse(event.data); // 处理步骤更新 }); // 监听所有任务 const eventSourceAll = new EventSource('/task/notification/sse/all'); ``` **SSE 端点**: - `GET /task/notification/sse?taskId=xxx` - 监听指定任务 - `GET /task/notification/sse/all` - 监听所有任务 - `POST /task/notification/close/{taskId}` - 关闭指定任务的SSE连接 - `POST /task/notification/close/all` - 关闭所有SSE连接 ## 📊 数据库设计 ### 核心表结构 #### device_config(设备配置表) - `id`:主键(BIGINT) - `device_id`:设备唯一标识(VARCHAR(50),唯一) - `device_code`:设备编码(VARCHAR(50),唯一) - `device_name`:设备名称(VARCHAR(100)) - `device_type`:设备类型(VARCHAR(50)) - `project_id`:所属项目ID(BIGINT) - `plc_ip`:PLC IP地址(VARCHAR(15)) - `plc_port`:PLC端口(INT) - `plc_type`:PLC类型(VARCHAR(20)) - `module_name`:模块名称(VARCHAR(50)) - `status`:设备状态(VARCHAR(20)) - `is_primary`:是否主控设备(BOOLEAN) - `enabled`:是否启用(BOOLEAN) - `config_json`:设备特定配置(TEXT,JSON格式) - `extra_params`:扩展参数(JSON) - `description`:设备描述(VARCHAR(200)) - `is_deleted`:是否删除(INT,0-否,1-是) - `created_time`、`updated_time`:创建/更新时间 - `created_by`、`updated_by`:创建/更新人 #### device_group_config(设备组配置表) - `id`:主键(BIGINT) - `group_code`:设备组编码(VARCHAR(50),唯一) - `group_name`:设备组名称(VARCHAR(100)) - `group_type`:设备组类型(INT,1-生产线,2-测试线,3-辅助设备组) - `project_id`:所属项目ID(BIGINT) - `status`:设备组状态(INT,0-停用,1-启用,3-维护中) - `max_concurrent_devices`:最大并发设备数(INT) - `heartbeat_interval`:心跳检测间隔(INT,秒) - `communication_timeout`:通信超时时间(INT,毫秒) - `description`:设备组描述(VARCHAR(200)) - `extra_config`:扩展配置(JSON) - `is_deleted`:是否删除(INT) - `created_time`、`updated_time`:创建/更新时间 - `created_by`、`updated_by`:创建/更新人 #### device_group_relation(设备组关系表) - `id`:主键(BIGINT) - `group_id`:设备组ID(BIGINT) - `device_id`:设备ID(BIGINT) - `priority`:设备在组内的优先级(INT,1-最高,10-最低) - `role`:设备在组内的角色(INT,1-主控,2-协作,3-监控) - `status`:设备在该组中的状态(INT,0-未配置,1-正常,2-故障,3-维护) - `connection_order`:连接顺序(INT,数值越小越先连接) - `relation_desc`:关联描述(VARCHAR(200)) - `extra_params`:扩展参数(JSON) - `is_deleted`:是否删除(INT) - `created_time`、`updated_time`:创建/更新时间 - `created_by`、`updated_by`:创建/更新人 #### multi_device_task(多设备任务表) - `id`:主键(BIGINT) - `task_id`:任务唯一标识(VARCHAR(50),唯一) - `group_id`:设备组ID(VARCHAR(50)) - `project_id`:项目ID(VARCHAR(50)) - `status`:任务状态(ENUM:PENDING, RUNNING, COMPLETED, FAILED, CANCELLED) - `current_step`:当前执行步骤(INT) - `total_steps`:总步骤数(INT) - `start_time`:开始时间(DATETIME) - `end_time`:结束时间(DATETIME) - `error_message`:错误信息(TEXT) - `result_data`:结果数据(JSON) - `created_time`、`updated_time`:创建/更新时间 #### task_step_detail(任务步骤详情表) - `id`:主键(BIGINT) - `task_id`:任务ID(VARCHAR(50)) - `step_order`:步骤顺序(INT) - `device_id`:设备ID(VARCHAR(50)) - `step_name`:步骤名称(VARCHAR(100)) - `status`:步骤状态(ENUM:PENDING, RUNNING, COMPLETED, FAILED, SKIPPED) - `start_time`:步骤开始时间(DATETIME) - `end_time`:步骤结束时间(DATETIME) - `duration_ms`:执行耗时(BIGINT,毫秒) - `input_data`:输入数据(JSON) - `output_data`:输出数据(JSON) - `error_message`:错误信息(TEXT) - `retry_count`:重试次数(INT) - `created_time`:创建时间(DATETIME) #### glass_info(玻璃信息表) - `id`:主键(BIGINT) - `glass_id`:玻璃ID(VARCHAR(50)) - `width`:宽度(DECIMAL) - `height`:高度(DECIMAL) - `work_line`:产线编号(VARCHAR(50)) - `scan_time`:扫码时间(DATETIME) - `status`:状态(VARCHAR(20)) - `created_time`、`updated_time`:创建/更新时间 #### device_status(设备状态监控表) - `id`:主键(BIGINT) - `device_id`:设备ID(VARCHAR(50)) - `task_id`:关联任务ID(VARCHAR(50),可选) - `status`:设备状态(ENUM:ONLINE, OFFLINE, BUSY, ERROR, MAINTENANCE) - `last_heartbeat`:最后心跳时间(DATETIME) - `cpu_usage`:CPU使用率(DECIMAL(5,2)) - `memory_usage`:内存使用率(DECIMAL(5,2)) - `plc_connection_status`:PLC连接状态(ENUM:CONNECTED, DISCONNECTED, ERROR) - `current_operation`:当前操作(VARCHAR(100)) - `operation_progress`:操作进度(DECIMAL(5,2),0-100) - `alert_message`:告警信息(TEXT) - `created_time`:记录时间(DATETIME) ## 🔄 任务执行流程 ### 串行执行流程 ``` 1. 创建任务记录(status = PENDING) 2. 获取设备组中的设备列表(按 connection_order 排序) 3. 依次执行每个设备: a. 检查前置条件 b. 更新步骤状态为 RUNNING c. 执行设备交互逻辑 d. 传递数据到下一个设备 e. 更新步骤状态为 COMPLETED 4. 所有设备执行完成后,更新任务状态为 COMPLETED ``` ### 并行执行流程 ``` 1. 创建任务记录(status = PENDING) 2. 获取设备组中的设备列表 3. 使用线程池并行执行设备: a. 使用 max_concurrent_devices 控制并发数 b. 每个设备独立执行 c. 等待所有设备完成 4. 所有设备执行完成后,更新任务状态为 COMPLETED ``` ## ⚙️ 配置说明 ### 应用配置(application.yml) ```yaml server: port: 10018 spring: profiles: active: dev application: name: plcSend liquibase: enabled: true change-log: classpath:changelog/changelogBase.xml # PLC配置 s7: load: dbArea: DB1 beginIndex: 0 raw: dbArea: DB2 beginIndex: 0 # PLC模拟配置 plc: simulate: enabled: false interval: 5000 failure-rate: 0 task-count: 10 task-type: normal # MES配置 mes: width: 2800 height: 5000 ``` ### 设备逻辑参数配置 每个设备类型的逻辑参数在 `extraParams.deviceLogic` 中配置,具体参数见各设备类型的说明。 ## 🛠️ 扩展开发 ### 添加新设备类型 1. **在 DeviceConfig.DeviceType 中添加常量** ```java public static final class DeviceType { public static final String NEW_DEVICE = "新设备类型"; } ``` 2. **创建设备处理器** ```java @Component public class NewDeviceLogicHandler extends BaseDeviceLogicHandler { @Override public String getDeviceType() { return DeviceConfig.DeviceType.NEW_DEVICE; } @Override protected DevicePlcVO.OperationResult doExecute( DeviceConfig deviceConfig, String operation, Map params, Map logicParams) { // 实现设备逻辑 } } ``` 3. **创建交互流程**(可选) ```java @Component public class NewDeviceInteraction implements DeviceInteraction { @Override public InteractionResult execute(InteractionContext context) { // 实现交互流程 } } ``` ### 添加设备协调逻辑 对于需要多实例协调的复杂设备,可以创建专用包: ``` interaction/ └── newdevice/ ├── handler/ ├── coordination/ └── model/ ``` ## 📝 注意事项 ### 1. 状态管理 - 大车设备的状态存储在内存中(`VehicleStatusManager`),服务重启后会丢失 - 如需持久化,可以扩展支持数据库存储 ### 2. 并发安全 - 状态管理器使用 `ConcurrentHashMap`,支持并发访问 - 任务执行使用线程池和 `max_concurrent_devices` 控制并发 ### 3. 错误处理 - 支持自动重试机制(默认最多3次) - 支持指数退避策略 - 错误分类:网络错误、超时错误可重试,业务错误不可重试 ### 4. 实时监控 - SSE 连接超时时间:30分钟 - 支持监听指定任务或所有任务 - 连接断开后需要重新连接 ### 5. 设备类型说明 - **卧式缓存**(`GLASS_STORAGE`):代码中已实现,但当前业务场景不使用,保留用于未来扩展 ## 🎯 已完成功能 ### ✅ 核心功能 - [x] 设备管理(配置、状态监控) - [x] 设备组管理(并发控制、优先级、角色) - [x] 多设备任务执行引擎(串行/并行) - [x] 设备协调服务(数据传递、状态同步) - [x] 实时监控推送(SSE) - [x] 错误处理和重试机制 ### ✅ 设备类型支持 - [x] 大车设备(多实例协调、状态管理、MES任务处理、进片/出片) - [x] 卧转立扫码(定时扫描、数据落库) - [x] 卧转立(30s缓冲、批量处理) - [x] 大理片笼(格子配置、逻辑判断) - [x] 卧式缓存(已实现,当前不使用) ### ✅ API 端点 - [x] 设备管理 API(`/device/*`) - [x] 设备组管理 API(`/device/group/*`) - [x] 多设备任务 API(`/device/task/*`) - [x] SSE 实时通知 API(`/task/notification/*`) ## 📚 相关文档 - 数据库迁移脚本:`src/main/resources/db/migration/` - API 文档:通过 Swagger 访问 `/swagger-ui.html` - 前端文档:见 `mes-web` 项目 ## 📞 联系方式 如有问题或建议,请联系开发团队。