opt:md文件优化
This commit is contained in:
@@ -2,7 +2,7 @@ package org.nl.acs.autoThread.autoRun;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nl.acs.autoThread.autoRunThread.service.enums.ThreadUsedStatusEnum;
|
||||
import org.nl.acs.autoThread.service.enums.ThreadUsedStatusEnum;
|
||||
import org.nl.acs.autoThread.service.enums.ThreadStatusEnum;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.nl.acs.autoThread.service.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import org.nl.acs.autoThread.autoRunThread.service.enums.ThreadUsedStatusEnum;
|
||||
import org.nl.acs.autoThread.service.enums.ThreadUsedStatusEnum;
|
||||
import org.nl.acs.autoThread.service.enums.ThreadStatusEnum;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.nl.acs.autoThread.autoRunThread.service.enums;
|
||||
package org.nl.acs.autoThread.service.enums;
|
||||
/**
|
||||
* Demo class
|
||||
*
|
||||
|
||||
@@ -7,7 +7,7 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.nl.ApplicationAutoInitial;
|
||||
import org.nl.acs.autoThread.autoRun.AbstractAutoRunnable;
|
||||
import org.nl.acs.autoThread.StartConfig;
|
||||
import org.nl.acs.autoThread.autoRunThread.service.enums.ThreadUsedStatusEnum;
|
||||
import org.nl.acs.autoThread.service.enums.ThreadUsedStatusEnum;
|
||||
import org.nl.acs.autoThread.service.AutoRunService;
|
||||
import org.nl.acs.autoThread.service.dto.AutoRunDto;
|
||||
import org.nl.common.exception.BadRequestException;
|
||||
|
||||
@@ -1,15 +1,415 @@
|
||||
### appInit
|
||||
项目启动时候对项目进行初始化,初始化器包括6项目
|
||||
1.AutoRunService :根据配置判断哪些自动线程需要启动
|
||||
2.自动线程继承AbstractAutoRunnable,目前系统一共有4个自动线程
|
||||
#### DeviceExecuteAutoRun
|
||||
设备自动线程,完成每个设备驱动的加载
|
||||
设备驱动通过while循环判断信号状态
|
||||
#### NDCAutoRun
|
||||
NDC自动线程,通过该线程与NDC创建socket通讯,做phace逻辑交互
|
||||
该版本废弃:统一改agvKit交互
|
||||
#### DeviceOpcSynchronizeAutoRun
|
||||
同步所有OpcService信号,
|
||||
该版本固定使用KEP-SERVER 进行信号同步
|
||||
#### SocketListenerAutoRun
|
||||
socket同步监听测试类,在startconfig中配置不用
|
||||
# 初始化自动线程文档
|
||||
|
||||
## 1. 自动线程系统概述
|
||||
|
||||
自动线程系统是 NL Admin System 的核心组件,负责管理系统启动时自动运行的后台任务。采用 **模板方法模式** + **服务发现机制**,实现线程的自动注册、启动和管理。
|
||||
|
||||
### 1.1 整体架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 应用启动阶段 │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ ApplicationAutoInitial (Spring自动初始化接口) │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ AutoRunServiceImpl.autoInitial() │
|
||||
│ │ │
|
||||
│ ├──► 扫描所有 AbstractAutoRunnable Bean │
|
||||
│ ├──► 过滤检查 (code空/重复/禁止列表) │
|
||||
│ ├──► 注册到 code_autoRun_Map │
|
||||
│ └──► 创建线程并启动 │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────┐ │
|
||||
│ │ AbstractAutoRunnable.run() │ │
|
||||
│ │ ┌─────────────────────────────────────────────┐ │ │
|
||||
│ │ │ before() → autoRun() → after() │ │ │
|
||||
│ │ │ │ │ │ │ │ │
|
||||
│ │ │ 前置处理 核心循环 后置清理 │ │ │
|
||||
│ │ └─────────────────────────────────────────────┘ │ │
|
||||
│ └─────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 1.2 核心组件
|
||||
|
||||
| 组件 | 职责 | 说明 |
|
||||
|------|------|------|
|
||||
| `ApplicationAutoInitial` | 自动初始化接口 | Spring启动时自动调用 `autoInitial()` |
|
||||
| `AutoRunServiceImpl` | 线程管理器 | 负责线程的注册、启动、停止、状态查询 |
|
||||
| `AbstractAutoRunnable` | 抽象基类 | 定义线程生命周期模板 |
|
||||
| `StartConfig` | 启动配置 | 控制全局开关和禁止列表 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 初始化流程
|
||||
|
||||
### 2.1 启动流程详解
|
||||
|
||||
```java
|
||||
// AutoRunServiceImpl.autoInitial()
|
||||
@Override
|
||||
public void autoInitial() throws Exception {
|
||||
// 1. 全局开关检查
|
||||
if (StartConfig.Need_Stop) {
|
||||
System.out.println("---未开启自动线程,AutoRun初始化终止---");
|
||||
return; // 全局禁止启动
|
||||
}
|
||||
|
||||
// 2. 遍历所有AbstractAutoRunnable Bean
|
||||
for (AbstractAutoRunnable autoRunnable : abstractAutoRunnableList) {
|
||||
// 检查1: code不能为空
|
||||
if (StringUtils.isEmpty(autoRunnable.getCode())) {
|
||||
autoRunnable.setMessage("code为空未加载");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查2: code不能重复
|
||||
if (partialJudg.contains(autoRunnable.getCode())) {
|
||||
autoRunnable.setMessage("code重复而未加载");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查3: 不在禁止列表中
|
||||
if (StartConfig.AutoRun_Ban.contains(autoRunnable.getCode())) {
|
||||
autoRunnable.setMessage("配置了禁止启动");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 通过所有检查,注册到Map
|
||||
autoRunnable.setUsedStatus(ThreadUsedStatusEnum.used);
|
||||
code_autoRun_Map.put(autoRunnable.getCode(), autoRunnable);
|
||||
}
|
||||
|
||||
// 3. 启动所有已注册的线程
|
||||
for (AbstractAutoRunnable autoRunnable : code_autoRun_Map.values()) {
|
||||
final Thread thread = new Thread(autoRunnable);
|
||||
code_Thread_Map.put(autoRunnable.getCode(), thread);
|
||||
thread.start();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 过滤规则
|
||||
|
||||
| 检查项 | 条件 | 处理方式 |
|
||||
|--------|------|----------|
|
||||
| **code为空** | `StringUtils.isEmpty(code)` | 跳过,记录消息 |
|
||||
| **code重复** | `partialJudg.contains(code)` | 跳过,记录消息 |
|
||||
| **在禁止列表** | `StartConfig.AutoRun_Ban.contains(code)` | 跳过,记录消息 |
|
||||
|
||||
---
|
||||
|
||||
## 3. AbstractAutoRunnable 抽象基类
|
||||
|
||||
### 3.1 类结构
|
||||
|
||||
```java
|
||||
@Data
|
||||
public abstract class AbstractAutoRunnable implements Runnable {
|
||||
private ThreadStatusEnum status; // 线程执行状态 (run/stop)
|
||||
private Date startTime; // 线程开始时间
|
||||
private Date stopTime; // 线程结束时间
|
||||
private String message; // 状态消息
|
||||
private ThreadUsedStatusEnum usedStatus; // 初始化状态 (used/unUsed)
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
this.setStatus(ThreadStatusEnum.run);
|
||||
this.setStartTime(new Date());
|
||||
try {
|
||||
this.setMessage("自动线程初始化中");
|
||||
this.before(); // 前置处理
|
||||
this.autoRun(); // 核心业务(子类实现死循环)
|
||||
this.setMessage("自动线程正常启动");
|
||||
} catch (Throwable throwable) {
|
||||
log.error(this.getCode() + "自动线程执行异常", throwable);
|
||||
} finally {
|
||||
this.setStopTime(new Date());
|
||||
this.setMessage("自动线程关闭");
|
||||
this.setStatus(ThreadStatusEnum.stop);
|
||||
this.after(); // 后置清理
|
||||
}
|
||||
}
|
||||
|
||||
// 子类必须实现的方法
|
||||
public abstract String getCode(); // 返回线程唯一标识
|
||||
public abstract String getName(); // 返回线程名称
|
||||
public abstract void autoRun() throws Exception; // 核心业务逻辑
|
||||
|
||||
// 可选覆盖方法
|
||||
public void before() throws Exception {} // 前置处理
|
||||
public void after() {} // 后置清理
|
||||
public void stop() { this.after(); } // 停止线程
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 生命周期方法
|
||||
|
||||
| 方法 | 调用时机 | 用途 | 是否必须实现 |
|
||||
|------|----------|------|--------------|
|
||||
| `before()` | `run()` 开始时 | 初始化资源、建立连接 | 否 |
|
||||
| `autoRun()` | `before()` 之后 | 核心业务逻辑(死循环) | **是** |
|
||||
| `after()` | `run()` 结束时 | 释放资源、清理 | 否 |
|
||||
| `stop()` | 手动停止时 | 触发停止流程 | 否 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 启动配置
|
||||
|
||||
### 4.1 StartConfig 配置类
|
||||
|
||||
```java
|
||||
public class StartConfig {
|
||||
/**
|
||||
* 全局开关:true=禁止所有自动线程启动,false=允许启动
|
||||
*/
|
||||
public static Boolean Need_Stop = Boolean.TRUE;
|
||||
|
||||
/**
|
||||
* 禁止启动的线程code列表
|
||||
*/
|
||||
public static List<String> AutoRun_Ban = new ArrayList<>();
|
||||
|
||||
static {
|
||||
AutoRun_Ban.add("TaskFeedbackAutoRun"); // 任务反馈线程(测试用)
|
||||
AutoRun_Ban.add("SocketListenerAutoRun"); // Socket监听线程(测试用)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 配置说明
|
||||
|
||||
| 配置项 | 类型 | 默认值 | 说明 |
|
||||
|--------|------|--------|------|
|
||||
| `Need_Stop` | Boolean | `true` | 全局开关,设为`false`时启动所有自动线程 |
|
||||
| `AutoRun_Ban` | List | 包含2个元素 | 精确匹配线程code,匹配到的线程不会启动 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 现有自动线程
|
||||
|
||||
### 5.1 线程列表
|
||||
|
||||
| 线程类 | Code | 职责 | 状态 |
|
||||
|--------|------|------|------|
|
||||
| `DeviceExecuteAutoRunable` | `DeviceExecuteAutoRun` | 设备执行线程,执行所有设备驱动 | **运行中** |
|
||||
| `OpcSignalSyncAutoRunnable` | `OpcSignalSyncAutoRun` | OPC信号同步线程 | **运行中** |
|
||||
| `SocketListenerAutoRun` | `SocketListenerAutoRun` | Socket监听测试线程 | **已禁止** |
|
||||
|
||||
### 5.2 DeviceExecuteAutoRunable
|
||||
|
||||
**职责**:定期执行所有设备驱动的自动任务
|
||||
|
||||
```java
|
||||
public class DeviceExecuteAutoRunable extends AbstractAutoRunnable {
|
||||
@Override
|
||||
public void autoRun() throws Exception {
|
||||
// 等待OPC同步完成(最多60秒)
|
||||
for (int i = 0; !OpcConfig.OPC_START_TAG; ++i) {
|
||||
Thread.sleep(1000L);
|
||||
if (i > 60) break;
|
||||
}
|
||||
|
||||
// 死循环执行设备任务
|
||||
while (true) {
|
||||
Thread.sleep(100);
|
||||
List<BaseDeviceDriver> deviceDrivers = deviceAppService.findDeviceDriver(BaseDeviceDriver.class);
|
||||
for (BaseDeviceDriver driver : deviceDrivers) {
|
||||
executorService.submit(() -> driver.executeAuto());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 OpcSignalSyncAutoRunnable
|
||||
|
||||
**职责**:同步所有OPC服务器的信号到系统内存
|
||||
|
||||
```java
|
||||
public class OpcSignalSyncAutoRunnable extends AbstractAutoRunnable {
|
||||
@Override
|
||||
public void autoRun() throws Exception {
|
||||
// 同步OPC信号逻辑
|
||||
while (true) {
|
||||
// 读取OPC服务器数据
|
||||
// 更新到统一数据访问器(UDW)
|
||||
Thread.sleep(50); // 控制同步频率
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 线程管理 API
|
||||
|
||||
### 6.1 AutoRunService 接口
|
||||
|
||||
```java
|
||||
public interface AutoRunService {
|
||||
/**
|
||||
* 启动指定线程
|
||||
* @param code 线程唯一标识
|
||||
*/
|
||||
void startThread(String code);
|
||||
|
||||
/**
|
||||
* 停止指定线程
|
||||
* @param code 线程唯一标识
|
||||
*/
|
||||
void stopThread(String code);
|
||||
|
||||
/**
|
||||
* 获取所有线程状态
|
||||
* @return 线程状态列表
|
||||
*/
|
||||
List<AutoRunDto> findAll();
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 使用示例
|
||||
|
||||
```java
|
||||
// 注入线程服务
|
||||
@Autowired
|
||||
private AutoRunService autoRunService;
|
||||
|
||||
// 启动线程
|
||||
autoRunService.startThread("DeviceExecuteAutoRun");
|
||||
|
||||
// 停止线程
|
||||
autoRunService.stopThread("DeviceExecuteAutoRun");
|
||||
|
||||
// 查询所有线程状态
|
||||
List<AutoRunDto> threads = autoRunService.findAll();
|
||||
for (AutoRunDto dto : threads) {
|
||||
System.out.println("线程: " + dto.getName() + ", 状态: " + dto.getStatus());
|
||||
}
|
||||
```
|
||||
|
||||
### 6.3 AutoRunDto 数据结构
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `code` | String | 线程唯一标识 |
|
||||
| `name` | String | 线程名称 |
|
||||
| `status` | String | 执行状态 (run/stop) |
|
||||
| `startTime` | Date | 启动时间 |
|
||||
| `stopTime` | Date | 停止时间 |
|
||||
| `message` | String | 状态消息 |
|
||||
| `thread_alive` | Boolean | 线程是否存活 |
|
||||
| `thread_name` | String | JVM线程名称 |
|
||||
| `thread_id` | String | JVM线程ID |
|
||||
| `thread_state` | String | JVM线程状态 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 扩展开发指南
|
||||
|
||||
### 7.1 创建新的自动线程
|
||||
|
||||
1. **继承 AbstractAutoRunnable**
|
||||
|
||||
```java
|
||||
@Component
|
||||
public class MyCustomAutoRun extends AbstractAutoRunnable {
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return "MyCustomAutoRun"; // 唯一标识
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "我的自定义线程";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void autoRun() throws Exception {
|
||||
// 死循环执行业务逻辑
|
||||
while (true) {
|
||||
// 执行任务...
|
||||
Thread.sleep(1000); // 控制执行频率
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void before() throws Exception {
|
||||
// 初始化资源(可选)
|
||||
super.before();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void after() {
|
||||
// 清理资源(可选)
|
||||
super.after();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **配置控制**
|
||||
|
||||
```java
|
||||
// 在 StartConfig 中配置(如需禁止启动)
|
||||
static {
|
||||
AutoRun_Ban.add("TaskFeedbackAutoRun");
|
||||
AutoRun_Ban.add("SocketListenerAutoRun");
|
||||
// AutoRun_Ban.add("MyCustomAutoRun"); // 如需禁止,取消注释
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2 注意事项
|
||||
|
||||
- **线程安全**:`autoRun()` 中的共享资源需要加锁保护
|
||||
- **异常处理**:建议在 `autoRun()` 内部捕获异常,避免线程意外终止
|
||||
- **退出机制**:建议使用 `volatile` 标志位控制循环退出
|
||||
|
||||
---
|
||||
|
||||
## 8. 关键设计要点
|
||||
|
||||
### 8.1 服务发现机制
|
||||
|
||||
Spring 自动扫描所有 `AbstractAutoRunnable` 子类:
|
||||
|
||||
```java
|
||||
@Autowired(required = false)
|
||||
private List<AbstractAutoRunnable> abstractAutoRunnableList;
|
||||
```
|
||||
|
||||
### 8.2 线程安全
|
||||
|
||||
```java
|
||||
@Override
|
||||
public synchronized void startThread(String code) { ... }
|
||||
|
||||
@Override
|
||||
public synchronized void stopThread(String threadCode) { ... }
|
||||
```
|
||||
|
||||
### 8.3 状态管理
|
||||
|
||||
使用枚举类管理状态:
|
||||
|
||||
```java
|
||||
// ThreadStatusEnum - 执行状态
|
||||
public enum ThreadStatusEnum {
|
||||
run, // 运行中
|
||||
stop // 已停止
|
||||
}
|
||||
|
||||
// ThreadUsedStatusEnum - 初始化状态
|
||||
public enum ThreadUsedStatusEnum {
|
||||
used, // 已使用(已注册)
|
||||
unUsed // 未使用(未注册)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v1.0
|
||||
**创建日期**: 2026年4月
|
||||
**适用模块**: NL Admin System - 自动线程模块
|
||||
|
||||
@@ -1,15 +1,509 @@
|
||||
### appInit
|
||||
项目启动时候对项目进行初始化,初始化器包括6项目
|
||||
1.AutoRunService :根据配置判断哪些自动线程需要启动
|
||||
2.自动线程继承AbstractAutoRunnable,目前系统一共有4个自动线程
|
||||
#### DeviceExecuteAutoRun
|
||||
设备自动线程,完成每个设备驱动的加载
|
||||
设备驱动通过while循环判断信号状态
|
||||
#### NDCAutoRun
|
||||
NDC自动线程,通过该线程与NDC创建socket通讯,做phace逻辑交互
|
||||
该版本废弃:统一改agvKit交互
|
||||
#### DeviceOpcSynchronizeAutoRun
|
||||
同步所有OpcService信号,
|
||||
该版本固定使用KEP-SERVER 进行信号同步
|
||||
#### SocketListenerAutoRun
|
||||
socket同步监听测试类,在startconfig中配置不用
|
||||
# 设备信息管理文档
|
||||
|
||||
## 1. 设备信息加载流程
|
||||
|
||||
### 1.1 整体架构
|
||||
|
||||
设备信息加载采用 **服务发现 + 驱动绑定** 的设计模式:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 应用启动阶段 │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ ApplicationAutoInitial (自动初始化接口) │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ DeviceAppServiceImpl.autoInitial() │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ reload() 方法 │ │
|
||||
│ │ 1. 从数据库查询设备基本信息 (DeviceMapper) │ │
|
||||
│ │ 2. 关联设备扩展信息 (DeviceExtraMapper) │ │
|
||||
│ │ 3. 关联OPC/PLC配置 (OpcMapper/OpcPlcMapper) │ │
|
||||
│ │ 4. 绑定设备驱动 (DeviceDriverDefination) │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||
│ │ 内存缓存 (devices List) │ │
|
||||
│ │ - devices: 设备对象列表 │ │
|
||||
│ │ - code_indexs: 设备编码索引 │ │
|
||||
│ └─────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 1.2 核心代码流程
|
||||
|
||||
#### ① 自动初始化触发
|
||||
|
||||
```java
|
||||
// DeviceAppServiceImpl.java
|
||||
@Override
|
||||
public void autoInitial() throws Exception {
|
||||
log.info("加载所有设备");
|
||||
this.reload(); // 核心加载方法
|
||||
}
|
||||
```
|
||||
|
||||
#### ② 设备信息查询与组装
|
||||
|
||||
```java
|
||||
@Override
|
||||
public synchronized void reload() {
|
||||
// 1. 查询所有设备(包含扩展信息)
|
||||
List<DeviceManageDto> deviceManageDtos = this.queryAllWithExtra();
|
||||
|
||||
// 2. 初始化内存缓存
|
||||
this.devices = new ArrayList();
|
||||
this.code_indexs = new ArrayList();
|
||||
|
||||
// 3. 遍历设备,创建Device对象并绑定驱动
|
||||
for (DeviceManageDto deviceManage : deviceManageDtos) {
|
||||
Device device = new Device();
|
||||
BeanUtil.copyProperties(deviceManage, device);
|
||||
this.devices.add(device);
|
||||
this.code_indexs.add(device.getDevice_code());
|
||||
|
||||
// 4. 绑定设备驱动(关键步骤)
|
||||
if (!StrUtil.isEmpty(device.getDriver_code())) {
|
||||
DeviceDriverDefination defination =
|
||||
deviceDriverDefinationAppService.getDeviceDriverDefination(deviceManage.getDriver_code());
|
||||
if (defination != null) {
|
||||
device.setDeviceDriverDefination(defination);
|
||||
DeviceDriver driver = defination.getDriverInstance(device); // 创建驱动实例
|
||||
device.setDeviceDriver(driver);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### ③ 数据库查询逻辑
|
||||
|
||||
`queryAllWithExtra()` 方法执行以下查询:
|
||||
|
||||
| 数据表 | 查询内容 | 用途 |
|
||||
|--------|----------|------|
|
||||
| `acs_device` | 设备基本信息 | 设备编码、名称、类型、地址等 |
|
||||
| `acs_device_extra` | 设备扩展属性 | 站点管理、自定义配置等 |
|
||||
| `acs_opc` | OPC服务器配置 | 设备通信连接信息 |
|
||||
| `acs_opc_plc` | PLC配置 | 设备PLC连接信息 |
|
||||
|
||||
### 1.3 设备驱动绑定机制
|
||||
|
||||
设备驱动采用 **策略模式**,通过 `DeviceDriverDefination` 动态创建驱动实例:
|
||||
|
||||
```java
|
||||
// DeviceDriverDefination.getDriverInstance(device)
|
||||
// 根据驱动定义,为每个设备创建对应的驱动实例
|
||||
DeviceDriver driver = defination.getDriverInstance(device);
|
||||
device.setDeviceDriver(driver);
|
||||
```
|
||||
|
||||
## 2. 设备信息数据结构
|
||||
|
||||
### 2.1 Device 实体
|
||||
|
||||
```java
|
||||
public class Device {
|
||||
private String device_code; // 设备编码(唯一标识)
|
||||
private String device_name; // 设备名称
|
||||
private String device_type; // 设备类型
|
||||
private String address; // 设备地址
|
||||
private String driver_code; // 驱动编码
|
||||
private String opc_server_id; // OPC服务器ID
|
||||
private String opc_plc_id; // PLC ID
|
||||
private DeviceDriver deviceDriver; // 设备驱动实例
|
||||
private DeviceDriverDefination deviceDriverDefination; // 驱动定义
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 DeviceDriver 抽象类
|
||||
|
||||
```java
|
||||
public abstract class DeviceDriver {
|
||||
private Device device; // 关联设备
|
||||
private String deviceCode; // 设备编码
|
||||
private DeviceDriverDefination deviceDriverDefination; // 驱动定义
|
||||
private boolean stop; // 停止标志
|
||||
|
||||
public DeviceDriver init(Device device, DeviceDriverDefination defination) {
|
||||
this.device = device;
|
||||
this.deviceCode = device.getDevice_code();
|
||||
this.deviceDriverDefination = defination;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 3. 设备信息使用方式
|
||||
|
||||
### 3.1 基础查询接口
|
||||
|
||||
```java
|
||||
// DeviceAppService 提供的查询方法
|
||||
|
||||
// 1. 查询所有设备
|
||||
List<Device> devices = deviceAppService.findAllDevice();
|
||||
|
||||
// 2. 根据设备编码查询
|
||||
Device device = deviceAppService.findDeviceByCode("DEVICE001");
|
||||
|
||||
// 3. 根据设备地址查询
|
||||
Device device = deviceAppService.findDeviceByAddress("A01-01");
|
||||
|
||||
// 4. 根据设备类型查询
|
||||
List<Device> devices = deviceAppService.findDeviceByType(DeviceType.STANDARD_INSPECT);
|
||||
|
||||
// 5. 获取设备驱动列表(按类型筛选)
|
||||
List<BaseDeviceDriver> drivers = deviceAppService.findDeviceDriver(BaseDeviceDriver.class);
|
||||
```
|
||||
|
||||
### 3.2 设备驱动调用
|
||||
|
||||
通过设备驱动执行具体业务操作:
|
||||
|
||||
```java
|
||||
// 获取设备驱动
|
||||
Device device = deviceAppService.findDeviceByCode("DEVICE001");
|
||||
DeviceDriver driver = device.getDeviceDriver();
|
||||
|
||||
// 执行设备操作(具体方法由子类实现)
|
||||
if (driver instanceof BaseDeviceDriver) {
|
||||
BaseDeviceDriver baseDriver = (BaseDeviceDriver) driver;
|
||||
baseDriver.executeAuto(); // 执行自动任务
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 自动线程调用
|
||||
|
||||
`DeviceExecuteAutoRunable` 自动线程定期执行设备任务:
|
||||
|
||||
```java
|
||||
// DeviceExecuteAutoRunable.autoRun()
|
||||
public void autoRun() throws Exception {
|
||||
// 等待OPC同步完成(最多60秒)
|
||||
for (int i = 0; !OpcConfig.OPC_START_TAG; ++i) {
|
||||
Thread.sleep(1000L);
|
||||
if (i > 60) break;
|
||||
}
|
||||
|
||||
// 循环执行设备任务
|
||||
while (true) {
|
||||
Thread.sleep(100);
|
||||
List<BaseDeviceDriver> deviceDrivers = deviceAppService.findDeviceDriver(BaseDeviceDriver.class);
|
||||
|
||||
for (BaseDeviceDriver driver : deviceDrivers) {
|
||||
// 提交到线程池执行
|
||||
executorService.submit(() -> driver.executeAuto());
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 设备驱动插件体系
|
||||
|
||||
设备驱动采用 **插件模式**,实现两个核心接口:
|
||||
|
||||
| 接口 | 职责 | 核心方法 |
|
||||
|------|------|----------|
|
||||
| `DriverExecutePlugin` | 设备执行逻辑 | `execute()` - 执行具体业务 |
|
||||
| `DeviceStageMonitorPlugin` | 设备状态监控 | `getDeviceStatusName()` - 获取状态 |
|
||||
|
||||
```java
|
||||
// DriverExecutePlugin 接口
|
||||
public interface DriverExecutePlugin {
|
||||
default void executeAuto() {
|
||||
try {
|
||||
this.execute(); // 调用子类实现
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
void execute() throws Exception; // 子类必须实现
|
||||
}
|
||||
|
||||
// DeviceStageMonitorPlugin 接口
|
||||
public interface DeviceStageMonitorPlugin {
|
||||
JSONObject getDeviceStatusName() throws Exception; // 获取设备状态
|
||||
void setDeviceStatus(JSONObject data); // 设置设备状态
|
||||
}
|
||||
```
|
||||
|
||||
### 3.5 OPC设备驱动使用
|
||||
|
||||
`AbstractOpcDeviceDriver` 是 OPC 设备驱动的基类,提供以下核心能力:
|
||||
|
||||
#### ① OPC信号读取
|
||||
|
||||
```java
|
||||
// 获取设备驱动
|
||||
Device device = deviceAppService.findDeviceByCode("DEVICE001");
|
||||
AbstractOpcDeviceDriver opcDriver = (AbstractOpcDeviceDriver) device.getDeviceDriver();
|
||||
|
||||
// 读取单个OPC信号值
|
||||
Integer value = opcDriver.getIntegeregerValue("heartbeat"); // 获取心跳值
|
||||
Object rawValue = opcDriver.getValue("running"); // 获取原始值
|
||||
|
||||
// 获取所有OPC点位配置
|
||||
List<OpcItemDto> opcItems = opcDriver.getOpcItems();
|
||||
for (OpcItemDto item : opcItems) {
|
||||
String itemCode = item.getItem_code();
|
||||
String deviceCode = item.getDevice_code();
|
||||
// 处理OPC点位
|
||||
}
|
||||
```
|
||||
|
||||
#### ② OPC信号写入
|
||||
|
||||
```java
|
||||
// 构建要写入的信号数据
|
||||
Map<String, Object> itemValues = new HashMap<>();
|
||||
itemValues.put("opc_server.plc.device001.start", 1); // 启动信号
|
||||
itemValues.put("opc_server.plc.device001.speed", 100); // 速度设置
|
||||
|
||||
// 调用控制方法(带重试机制)
|
||||
opcDriver.checkcontrol(itemValues);
|
||||
|
||||
// 或者直接调用control方法
|
||||
boolean result = opcDriver.control(itemValues);
|
||||
if (!result) {
|
||||
throw new RuntimeException("OPC写入失败");
|
||||
}
|
||||
```
|
||||
|
||||
#### ③ 获取设备扩展信息
|
||||
|
||||
```java
|
||||
// 获取设备扩展配置
|
||||
Map<String, Object> extraValues = opcDriver.getExtraValue();
|
||||
String stationManager = (String) extraValues.get("station_manager");
|
||||
|
||||
// 获取设备连接信息
|
||||
String opcServer = opcDriver.getOpcServer(); // OPC服务器编码
|
||||
String opcPlc = opcDriver.getOpcPlc(); // PLC编码
|
||||
String deviceCode = opcDriver.getDeviceCode(); // 设备编码
|
||||
```
|
||||
|
||||
### 3.6 驱动执行上下文
|
||||
|
||||
每个驱动实例持有设备信息和统一数据访问器:
|
||||
|
||||
```java
|
||||
// 获取关联设备
|
||||
Device device = driver.getDevice();
|
||||
|
||||
// 获取驱动定义
|
||||
DeviceDriverDefination defination = driver.getDriverDefination();
|
||||
|
||||
// 获取统一数据访问器(用于读写OPC数据)
|
||||
UnifiedDataAccessor opcUdw = opcDriver.getOpcValueAccessor();
|
||||
Object value = opcUdw.getValue("opc_server.plc.device001.status");
|
||||
```
|
||||
|
||||
## 4. 业务场景示例
|
||||
|
||||
### 4.1 场景一:设备状态监控
|
||||
|
||||
```java
|
||||
// 查询所有设备状态
|
||||
List<Device> devices = deviceAppService.findAllDevice();
|
||||
for (Device device : devices) {
|
||||
DeviceDriver driver = device.getDeviceDriver();
|
||||
if (driver instanceof AbstractOpcDeviceDriver) {
|
||||
AbstractOpcDeviceDriver opcDriver = (AbstractOpcDeviceDriver) driver;
|
||||
List<OpcItemDto> opcItems = opcDriver.getOpcItems();
|
||||
// 处理OPC信号数据
|
||||
}
|
||||
|
||||
// 获取设备状态名称(故障、联机等)
|
||||
if (driver instanceof DeviceStageMonitorPlugin) {
|
||||
DeviceStageMonitorPlugin monitor = (DeviceStageMonitorPlugin) driver;
|
||||
JSONObject status = monitor.getDeviceStatusName();
|
||||
String statusName = status.getString("statusName");
|
||||
System.out.println("设备 " + device.getDevice_code() + " 状态: " + statusName);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 场景二:设备指令执行
|
||||
|
||||
```java
|
||||
// 根据设备编码执行指令
|
||||
String deviceCode = "CONVEYOR001";
|
||||
Device device = deviceAppService.findDeviceByCode(deviceCode);
|
||||
|
||||
if (device != null && device.getDeviceDriver() instanceof BaseDeviceDriver) {
|
||||
BaseDeviceDriver driver = (BaseDeviceDriver) device.getDeviceDriver();
|
||||
driver.executeAuto(); // 执行设备自动任务
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 场景三:设备动态管理
|
||||
|
||||
```java
|
||||
// 运行时添加设备
|
||||
deviceAppService.addDevice("NEW_DEVICE_001");
|
||||
|
||||
// 运行时移除设备
|
||||
deviceAppService.removeDevice("DEVICE_TO_REMOVE");
|
||||
|
||||
// 重新加载所有设备
|
||||
deviceAppService.reload();
|
||||
```
|
||||
|
||||
### 4.4 场景四:OPC信号批量写入
|
||||
|
||||
```java
|
||||
// 批量控制多个设备
|
||||
List<String> deviceCodes = Arrays.asList("CONVEYOR001", "CONVEYOR002", "CONVEYOR003");
|
||||
|
||||
for (String deviceCode : deviceCodes) {
|
||||
Device device = deviceAppService.findDeviceByCode(deviceCode);
|
||||
if (device != null && device.getDeviceDriver() instanceof AbstractOpcDeviceDriver) {
|
||||
AbstractOpcDeviceDriver opcDriver = (AbstractOpcDeviceDriver) device.getDeviceDriver();
|
||||
|
||||
// 构建控制信号
|
||||
Map<String, Object> signals = new HashMap<>();
|
||||
signals.put(opcDriver.getItem("start"), 1);
|
||||
signals.put(opcDriver.getItem("speed"), 50);
|
||||
|
||||
// 执行写入(带重试机制)
|
||||
try {
|
||||
opcDriver.checkcontrol(signals);
|
||||
log.info("设备 {} 控制成功", deviceCode);
|
||||
} catch (Exception e) {
|
||||
log.error("设备 {} 控制失败: {}", deviceCode, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.5 场景五:设备状态同步
|
||||
|
||||
```java
|
||||
// 从OPC读取设备状态并更新到系统
|
||||
String deviceCode = "LIFT001";
|
||||
Device device = deviceAppService.findDeviceByCode(deviceCode);
|
||||
|
||||
if (device != null && device.getDeviceDriver() instanceof AbstractOpcDeviceDriver) {
|
||||
AbstractOpcDeviceDriver opcDriver = (AbstractOpcDeviceDriver) device.getDeviceDriver();
|
||||
|
||||
// 读取多个信号
|
||||
Integer heartbeat = opcDriver.getIntegeregerValue("heartbeat");
|
||||
Integer running = opcDriver.getIntegeregerValue("running");
|
||||
Integer fault = opcDriver.getIntegeregerValue("fault");
|
||||
|
||||
// 构建状态数据
|
||||
JSONObject statusData = new JSONObject();
|
||||
statusData.put("deviceCode", deviceCode);
|
||||
statusData.put("heartbeat", heartbeat);
|
||||
statusData.put("running", running == 1);
|
||||
statusData.put("fault", fault == 1);
|
||||
|
||||
// 更新设备状态
|
||||
DeviceStageMonitorPlugin monitor = (DeviceStageMonitorPlugin) opcDriver;
|
||||
monitor.setDeviceStatus(statusData);
|
||||
|
||||
// 存储到数据库或缓存
|
||||
deviceStatusService.updateStatus(deviceCode, statusData);
|
||||
}
|
||||
```
|
||||
|
||||
### 4.6 场景六:自定义驱动执行
|
||||
|
||||
```java
|
||||
// 创建自定义任务执行器
|
||||
public class CustomDeviceTask implements Runnable {
|
||||
private BaseDeviceDriver driver;
|
||||
|
||||
public CustomDeviceTask(BaseDeviceDriver driver) {
|
||||
this.driver = driver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// 执行前置检查
|
||||
if (!checkDeviceReady(driver)) {
|
||||
log.warn("设备 {} 未就绪", driver.getDeviceCode());
|
||||
return;
|
||||
}
|
||||
|
||||
// 执行驱动逻辑
|
||||
driver.execute();
|
||||
|
||||
// 记录执行日志
|
||||
log.info("设备 {} 任务执行完成", driver.getDeviceCode());
|
||||
} catch (Exception e) {
|
||||
log.error("设备 {} 任务执行失败: {}", driver.getDeviceCode(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkDeviceReady(BaseDeviceDriver driver) {
|
||||
// 检查设备状态、连接状态等
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 使用示例
|
||||
BaseDeviceDriver driver = deviceAppService.findDeviceDriver("CONVEYOR001");
|
||||
if (driver != null) {
|
||||
executorService.submit(new CustomDeviceTask(driver));
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 关键设计要点
|
||||
|
||||
### 5.1 内存缓存策略
|
||||
|
||||
| 设计点 | 说明 |
|
||||
|--------|------|
|
||||
| **缓存时机** | 应用启动时加载,运行时动态更新 |
|
||||
| **缓存结构** | `devices` 列表 + `code_indexs` 索引 |
|
||||
| **线程安全** | 使用 `synchronized` 和 `Collections.synchronizedList()` |
|
||||
| **更新机制** | 提供 `reload()`、`addDevice()`、`removeDevice()` 方法 |
|
||||
|
||||
### 5.2 驱动解耦设计
|
||||
|
||||
- **策略模式**:通过 `DeviceDriverDefination` 解耦驱动定义与实现
|
||||
- **依赖注入**:Spring 自动扫描驱动实现类
|
||||
- **动态创建**:根据 `driver_code` 动态创建对应驱动实例
|
||||
|
||||
### 5.3 配置校验
|
||||
|
||||
在加载设备时进行多重校验:
|
||||
|
||||
```java
|
||||
// queryAllWithExtra() 中的校验逻辑
|
||||
if (opc == null) {
|
||||
log.info("设备:{},配置的OPC数据源不存在", device_code);
|
||||
continue; // 跳过无效配置
|
||||
}
|
||||
if (opcPlc == null) {
|
||||
log.info("设备:{},配置的PLC数据源不存在", device_code);
|
||||
continue; // 跳过无效配置
|
||||
}
|
||||
```
|
||||
|
||||
## 6. 扩展开发指南
|
||||
|
||||
### 6.1 添加新设备类型
|
||||
|
||||
1. 在数据库中添加设备记录(`acs_device` 表)
|
||||
2. 配置设备扩展信息(`acs_device_extra` 表)
|
||||
3. 配置 OPC/PLC 连接信息(`acs_opc`、`acs_opc_plc` 表)
|
||||
4. 确保对应的驱动已注册
|
||||
|
||||
### 6.2 添加新设备驱动
|
||||
|
||||
1. 继承 `DeviceDriver` 抽象类
|
||||
2. 实现具体的业务逻辑方法
|
||||
3. 在 `DeviceDriverDefination` 中注册驱动
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v1.0
|
||||
**创建日期**: 2026年4月
|
||||
**适用模块**: NL Admin System - 设备管理模块
|
||||
|
||||
@@ -1,7 +1,334 @@
|
||||
### storageMgt
|
||||
货位管理模块:主要是AGV取放货的点
|
||||
1.货位编码与上位系统保持一致
|
||||
2.AGV地址有2个,正常逻辑取放地址是同一个,如果取放货位不一样需要配合adress1共同使用
|
||||
3.offset:货位偏移量:主要用于ACSKit套件对接,AGV到达取放货位时会请求取放货,这时通过offset偏移量来下发给kit
|
||||
4.has:有无货状态,AGV取放货完成后更新该状态
|
||||
# 设备协议管理文档
|
||||
|
||||
## 1. 设备协议概述
|
||||
|
||||
设备协议模块负责管理设备与PLC之间的通信协议配置,主要功能包括:
|
||||
|
||||
- 设备协议信息查询
|
||||
- 协议数据导出(支持多种PLC类型)
|
||||
- 协议格式校验与转换
|
||||
|
||||
### 1.1 协议数据结构
|
||||
|
||||
设备协议数据存储在 `acs_device_extra` 表中,核心字段:
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| `device_id` | VARCHAR | 关联设备ID |
|
||||
| `extra_code` | VARCHAR | 协议编码(格式:OPC_SERVER.PLC.DEVICE.CODE) |
|
||||
| `extra_name` | VARCHAR | 协议名称(PLC地址,如 DB100.B1) |
|
||||
| `extra_value` | VARCHAR | 协议值 |
|
||||
| `filed_type` | VARCHAR | 字段类型(02-输入点位,03-输出点位) |
|
||||
|
||||
### 1.2 协议编码格式
|
||||
|
||||
协议编码采用 **四级分层结构**:
|
||||
|
||||
```
|
||||
OPC_SERVER_CODE.PLC_CODE.DEVICE_CODE.POINT_CODE
|
||||
↓ ↓ ↓ ↓
|
||||
RD1 RD1 A1 mode
|
||||
(OPC服务器) (PLC编码) (设备编码) (点位编码)
|
||||
```
|
||||
|
||||
示例:`RD1.RD1.A1.mode`
|
||||
|
||||
---
|
||||
|
||||
## 2. 核心服务接口
|
||||
|
||||
### 2.1 DeviceProtocolService
|
||||
|
||||
```java
|
||||
public interface DeviceProtocolService {
|
||||
|
||||
/**
|
||||
* 分页查询设备协议
|
||||
* @param whereJson 查询条件
|
||||
* @param page 分页参数
|
||||
* @return 分页结果
|
||||
*/
|
||||
Map<String, Object> queryDeviceProtocol(Map whereJson, Pageable page);
|
||||
|
||||
/**
|
||||
* 查询设备协议列表(不分页)
|
||||
* @param whereJson 查询条件
|
||||
* @return 协议列表
|
||||
*/
|
||||
JSONArray queryDeviceProtocol(Map whereJson);
|
||||
|
||||
/**
|
||||
* 导出设备DB协议(Excel格式)
|
||||
* @param jsonarr 协议数据
|
||||
* @param response HTTP响应
|
||||
*/
|
||||
void downDeviceDBload(JSONArray jsonarr, HttpServletResponse response) throws IOException;
|
||||
|
||||
/**
|
||||
* 导出Smart设备协议CSV
|
||||
* @param queryDeviceProtocol 协议数据
|
||||
* @param response HTTP响应
|
||||
*/
|
||||
void downDeviceDBloadSmartCSV(JSONArray queryDeviceProtocol, HttpServletResponse response);
|
||||
|
||||
/**
|
||||
* 导出FX5U设备协议CSV
|
||||
* @param queryDeviceProtocol 协议数据
|
||||
* @param response HTTP响应
|
||||
*/
|
||||
void downDeviceDBloadFX5UCSV(JSONArray queryDeviceProtocol, HttpServletResponse response);
|
||||
|
||||
/**
|
||||
* 导出通用CSV(西门子1200/1500)
|
||||
* @param queryDeviceProtocol 协议数据
|
||||
* @param response HTTP响应
|
||||
*/
|
||||
void downDeviceDBloadCSV(JSONArray queryDeviceProtocol, HttpServletResponse response);
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 查询条件说明
|
||||
|
||||
| 参数名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| `device_types` | String | 设备类型筛选 |
|
||||
| `blurry` | String | 模糊搜索(设备编码或名称) |
|
||||
| `opc_id` | String | OPC服务器ID筛选 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 协议导出功能
|
||||
|
||||
### 3.1 支持的PLC类型
|
||||
|
||||
| PLC类型 | 导出方法 | 数据类型映射 |
|
||||
|---------|----------|--------------|
|
||||
| **西门子200 Smart** | `downDeviceDBloadSmartCSV()` | W→Word, D→DWord, 含"."→Boolean |
|
||||
| **三菱FX5U** | `downDeviceDBloadFX5UCSV()` | D→Long, 含"."→Boolean |
|
||||
| **西门子1200/1500** | `downDeviceDBloadCSV()` | DBx.By→Byte/Boolean, W→Word, D→DWord |
|
||||
|
||||
### 3.2 CSV导出格式
|
||||
|
||||
导出的CSV文件包含以下列:
|
||||
|
||||
| 列名 | 说明 | 示例 |
|
||||
|------|------|------|
|
||||
| **Tag Name** | 点位编码 | `mode` |
|
||||
| **Address** | PLC地址 | `DB100.B1.0` |
|
||||
| **Data Type** | 数据类型 | `Boolean` / `Word` / `DWord` |
|
||||
| **Respect Data Type** | 保留字段 | `1` |
|
||||
| **Client Access** | 访问权限 | `R/W` |
|
||||
| **Scan Rate** | 扫描速率(ms) | `100` |
|
||||
|
||||
### 3.3 协议格式校验
|
||||
|
||||
在导出前会进行格式校验:
|
||||
|
||||
```java
|
||||
// 校验协议编码格式(必须包含3个点)
|
||||
int num = countStr(extra_code, ".");
|
||||
if (num != 3) {
|
||||
throw new BadRequestException("协议编码格式不正确: " + extra_code);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 数据类型映射规则
|
||||
|
||||
### 4.1 西门子200 Smart 映射规则
|
||||
|
||||
```java
|
||||
String datatype = jo.getString("extra_name");
|
||||
if (!datatype.contains(".")) {
|
||||
String[] split = datatype.split("");
|
||||
if (split[1].equals("W")) {
|
||||
datatype = "Word"; // 如 VW100 → Word
|
||||
} else if (split[1].equals("D")) {
|
||||
datatype = "DWord"; // 如 VD100 → DWord
|
||||
}
|
||||
} else {
|
||||
datatype = "Boolean"; // 如 I0.0 → Boolean
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 三菱FX5U 映射规则
|
||||
|
||||
```java
|
||||
if (!datatype.contains(".")) {
|
||||
String[] split = datatype.split("");
|
||||
if (split[1].equals("D")) {
|
||||
datatype = "Long"; // 如 D100 → Long
|
||||
}
|
||||
} else {
|
||||
datatype = "Boolean"; // 如 X0.0 → Boolean
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 西门子1200/1500 映射规则
|
||||
|
||||
```java
|
||||
if (datatype.startsWith("DB")) {
|
||||
String str1 = datatype.substring(0, datatype.indexOf("."));
|
||||
String headtype = datatype.substring(str1.length() + 1);
|
||||
|
||||
if (headtype.startsWith("B")) {
|
||||
if (headtype.contains(".")) {
|
||||
datatype = "Boolean"; // DB100.B1.0 → Boolean
|
||||
} else {
|
||||
datatype = "Byte"; // DB100.B1 → Byte
|
||||
}
|
||||
} else if (headtype.startsWith("W")) {
|
||||
datatype = "Word"; // DB100.W1 → Word
|
||||
} else if (headtype.startsWith("D")) {
|
||||
datatype = "DWord"; // DB100.D1 → DWord
|
||||
} else if (headtype.startsWith("S")) {
|
||||
datatype = "String"; // DB100.S1 → String
|
||||
} else if (headtype.startsWith("REAL")) {
|
||||
datatype = "REAL"; // DB100.REAL1 → REAL
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 使用示例
|
||||
|
||||
### 5.1 查询设备协议
|
||||
|
||||
```java
|
||||
// 构建查询条件
|
||||
Map<String, Object> whereJson = new HashMap<>();
|
||||
whereJson.put("device_types", "CONVEYOR"); // 筛选设备类型
|
||||
whereJson.put("blurry", "A1"); // 模糊搜索
|
||||
whereJson.put("opc_id", "OPC_SERVER_01"); // 筛选OPC服务器
|
||||
|
||||
// 分页查询
|
||||
Pageable page = PageRequest.of(0, 10);
|
||||
Map<String, Object> result = deviceProtocolService.queryDeviceProtocol(whereJson, page);
|
||||
|
||||
// 不分页查询
|
||||
JSONArray protocols = deviceProtocolService.queryDeviceProtocol(whereJson);
|
||||
```
|
||||
|
||||
### 5.2 导出协议CSV
|
||||
|
||||
```java
|
||||
// 查询协议数据
|
||||
JSONArray protocols = deviceProtocolService.queryDeviceProtocol(whereJson);
|
||||
|
||||
// 导出西门子1200/1500格式
|
||||
deviceProtocolService.downDeviceDBloadCSV(protocols, response);
|
||||
|
||||
// 或者导出西门子200 Smart格式
|
||||
deviceProtocolService.downDeviceDBloadSmartCSV(protocols, response);
|
||||
|
||||
// 或者导出三菱FX5U格式
|
||||
deviceProtocolService.downDeviceDBloadFX5UCSV(protocols, response);
|
||||
```
|
||||
|
||||
### 5.3 导出协议Excel
|
||||
|
||||
```java
|
||||
JSONArray protocols = deviceProtocolService.queryDeviceProtocol(whereJson);
|
||||
deviceProtocolService.downDeviceDBload(protocols, response);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 业务场景
|
||||
|
||||
### 6.1 场景一:批量导出PLC配置
|
||||
|
||||
```java
|
||||
// 查询所有设备协议
|
||||
Map<String, Object> whereJson = new HashMap<>();
|
||||
JSONArray protocols = deviceProtocolService.queryDeviceProtocol(whereJson);
|
||||
|
||||
// 根据PLC类型选择导出方法
|
||||
String plcType = "SIEMENS_1200";
|
||||
switch (plcType) {
|
||||
case "SIEMENS_200SMART":
|
||||
deviceProtocolService.downDeviceDBloadSmartCSV(protocols, response);
|
||||
break;
|
||||
case "MITSUBISHI_FX5U":
|
||||
deviceProtocolService.downDeviceDBloadFX5UCSV(protocols, response);
|
||||
break;
|
||||
case "SIEMENS_1200":
|
||||
case "SIEMENS_1500":
|
||||
default:
|
||||
deviceProtocolService.downDeviceDBloadCSV(protocols, response);
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 场景二:按设备类型导出
|
||||
|
||||
```java
|
||||
// 只导出特定类型设备的协议
|
||||
Map<String, Object> whereJson = new HashMap<>();
|
||||
whereJson.put("device_types", "LIFT"); // 只导出提升机设备
|
||||
|
||||
JSONArray protocols = deviceProtocolService.queryDeviceProtocol(whereJson);
|
||||
deviceProtocolService.downDeviceDBloadCSV(protocols, response);
|
||||
```
|
||||
|
||||
### 6.3 场景三:前端API调用
|
||||
|
||||
```javascript
|
||||
// 查询协议列表
|
||||
fetch('/api/deviceProtocol', {
|
||||
method: 'GET',
|
||||
params: {
|
||||
device_types: 'CONVEYOR',
|
||||
blurry: 'A1'
|
||||
}
|
||||
}).then(res => res.json())
|
||||
.then(data => console.log(data));
|
||||
|
||||
// 导出CSV
|
||||
window.open('/api/deviceProtocol/export?plcType=SIEMENS_1200');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 关键设计要点
|
||||
|
||||
### 7.1 协议编码规范
|
||||
|
||||
协议编码必须遵循以下格式:
|
||||
|
||||
```
|
||||
OPC_SERVER.PLC.DEVICE.POINT
|
||||
```
|
||||
|
||||
**示例**:
|
||||
- `RD1.RD1.A1.mode` - A1设备的mode点位
|
||||
- `OPC_SRV01.PLC01.CONV001.start` - CONV001设备的start点位
|
||||
|
||||
### 7.2 数据类型自动识别
|
||||
|
||||
系统根据协议名称自动识别数据类型:
|
||||
|
||||
| 协议名称特征 | 识别的数据类型 |
|
||||
|--------------|----------------|
|
||||
| 包含 `.` 且以数字结尾 | Boolean(如 DB100.B1.0) |
|
||||
| 以 `W` 开头(不含`.`) | Word(如 VW100) |
|
||||
| 以 `D` 开头(不含`.`) | DWord 或 Long |
|
||||
| 以 `DB` 开头 | 根据后续字符判断 |
|
||||
|
||||
### 7.3 协议分类
|
||||
|
||||
根据 `filed_type` 字段区分协议类型:
|
||||
|
||||
| filed_type | 含义 | 用途 |
|
||||
|------------|------|------|
|
||||
| `01` | 设备属性 | 设备基础配置(不参与协议导出) |
|
||||
| `02` | 输入点位 | PLC输入信号(如传感器状态) |
|
||||
| `03` | 输出点位 | PLC输出信号(如控制指令) |
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v1.0
|
||||
**创建日期**: 2026年4月
|
||||
**适用模块**: NL Admin System - 设备协议模块
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
|
||||
加载所有设备信息devices至本地内存
|
||||
#### 3.StorageCellServiceImpl
|
||||
加载货位信息至内存
|
||||
加载货位信息至内存
|
||||
#### NDCAutoRun
|
||||
NDC自动线程,通过该线程与NDC创建socket通讯,做phace逻辑交互
|
||||
该版本废弃:统一改agvKit交互
|
||||
NDC自动线程,通过该线程与NDC创建socket通讯,做phace逻辑交互
|
||||
该版本废弃:统一改agvKit交互
|
||||
#### DeviceOpcSynchronizeAutoRun
|
||||
同步所有OpcService信号,
|
||||
该版本固定使用KEP-SERVER 进行信号同步
|
||||
|
||||
Reference in New Issue
Block a user