feat: da测试
This commit is contained in:
@@ -16,15 +16,8 @@ import org.nl.iot.modular.iot.entity.IotConnect;
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RValue {
|
||||
/**
|
||||
* 设备
|
||||
*/
|
||||
// private DeviceBO device;
|
||||
|
||||
/**
|
||||
* 位号 - 子设备
|
||||
*/
|
||||
// private PointBO point;
|
||||
// private String connectId;
|
||||
// private String deviceCode;
|
||||
/**
|
||||
* 配置
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.nl.iot.core.driver.protocol.opcda;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jinterop.dcom.common.JIException;
|
||||
@@ -78,7 +79,7 @@ public class OpcDaProtocolDriverImpl implements DriverCustomService {
|
||||
String host = driverConfig.get("host").getValueByClass(String.class);
|
||||
String clsId = driverConfig.get("clsId").getValueByClass(String.class);
|
||||
String user = driverConfig.get("username").getValueByClass(String.class);
|
||||
String password = driverConfig.get("password").getValueByClass(String.class);
|
||||
String password = ObjectUtil.isEmpty(driverConfig.get("password").getValue()) ? "" : driverConfig.get("password").getValueByClass(String.class);
|
||||
ConnectionInformation connectionInformation = new ConnectionInformation(host, clsId, user, password);
|
||||
server = new Server(connectionInformation, Executors.newSingleThreadScheduledExecutor());
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.nl.iot.core.driver.service;
|
||||
|
||||
/**
|
||||
* 自定义通信协议驱动工厂
|
||||
* @author: lyd
|
||||
* @date: 2026/3/2
|
||||
*/
|
||||
public class DriverCustomFactory {
|
||||
}
|
||||
@@ -497,16 +497,38 @@ public class ApiTest {
|
||||
opcDaProtocolDriver.initial();
|
||||
|
||||
// 构建驱动配置(连接配置)
|
||||
// 重要提示:
|
||||
// 1. 本地连接使用 "127.0.0.1" 或 "localhost"
|
||||
// 2. username 格式:
|
||||
// - 本地用户:直接使用用户名,如 "Administrator" 或 "YourUsername"
|
||||
// - 域用户:使用 "DOMAIN\\username" 格式
|
||||
// - 如果 OPC 服务器配置为允许匿名访问,可以尝试空字符串
|
||||
// 3. password 必须是 Windows 用户的实际密码
|
||||
// 4. 确保 Windows DCOM 配置正确(参考 Matrikon OPC 文档)
|
||||
|
||||
Map<String, AttributeBO> driverConfig = new HashMap<>();
|
||||
driverConfig.put("host", AttributeBO.builder().value("localhost").build());
|
||||
driverConfig.put("clsId", AttributeBO.builder().value("F8582CF2-88FB-11D0-B850-00C0F0104305").build()); // OPC DA Server CLSID
|
||||
driverConfig.put("username", AttributeBO.builder().value("Administrator").build());
|
||||
driverConfig.put("password", AttributeBO.builder().value("password").build());
|
||||
driverConfig.put("host", AttributeBO.builder().value("127.0.0.1").build());
|
||||
driverConfig.put("clsId", AttributeBO.builder().value("F8582CF2-88FB-11D0-B850-00C0F0104305").build());
|
||||
|
||||
// 方案1:使用当前登录用户(推荐本地测试)
|
||||
// 获取当前 Windows 用户名:在 CMD 中运行 "echo %USERNAME%"
|
||||
String currentUser = System.getProperty("user.name"); // 获取当前 Java 进程的用户名
|
||||
// driverConfig.put("username", AttributeBO.builder().value(currentUser).build());
|
||||
// driverConfig.put("password", AttributeBO.builder().value("6614").build()); // 替换为你的 Windows 密码
|
||||
|
||||
// 方案2:如果模拟器配置了特定用户,使用该用户
|
||||
driverConfig.put("username", AttributeBO.builder().value("Administrator").build());
|
||||
driverConfig.put("password", AttributeBO.builder().value("12356").build());
|
||||
|
||||
// 方案3:尝试匿名访问(某些 OPC 服务器支持)
|
||||
// driverConfig.put("username", AttributeBO.builder().value("").build());
|
||||
// driverConfig.put("password", AttributeBO.builder().value("").build());
|
||||
|
||||
// 构建点位配置
|
||||
// 根据你的模拟器截图,Item ID 是 "Random.Int1"
|
||||
Map<String, AttributeBO> pointConfig = new HashMap<>();
|
||||
pointConfig.put("group", AttributeBO.builder().value("Group1").build()); // 组名
|
||||
pointConfig.put("tag", AttributeBO.builder().value("Channel1.Device1.Tag1").build()); // 标签名
|
||||
pointConfig.put("group", AttributeBO.builder().value("Group0").build()); // 组名
|
||||
pointConfig.put("tag", AttributeBO.builder().value("Random.Int1").build()); // 标签名,与模拟器中的 Item ID 一致
|
||||
|
||||
// 构建连接对象
|
||||
IotConnect connect = IotConnect.builder()
|
||||
@@ -524,7 +546,7 @@ public class ApiTest {
|
||||
.connectId(1)
|
||||
.alias("sensor1")
|
||||
.aliasName("传感器1")
|
||||
.registerAddress("Channel1.Device1.Tag1")
|
||||
.registerAddress("Random.Int1")
|
||||
.dataType("int")
|
||||
.readonly(true)
|
||||
.enabled(true)
|
||||
|
||||
261
nl-web-app/src/test/java/org/nl/OpcDaConnectionTest.java
Normal file
261
nl-web-app/src/test/java/org/nl/OpcDaConnectionTest.java
Normal file
@@ -0,0 +1,261 @@
|
||||
package org.nl;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.nl.iot.core.driver.bo.AttributeBO;
|
||||
import org.nl.iot.core.driver.entity.RValue;
|
||||
import org.nl.iot.core.driver.protocol.opcda.OpcDaProtocolDriverImpl;
|
||||
import org.nl.iot.modular.iot.entity.IotConfig;
|
||||
import org.nl.iot.modular.iot.entity.IotConnect;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* OPC DA 连接测试 - 多种认证方案
|
||||
*
|
||||
* 使用说明:
|
||||
* 1. 确保 Matrikon OPC 模拟器正在运行
|
||||
* 2. 确保已配置 DCOM 权限(参考 OPC_DA_DCOM_完整配置指南.md)
|
||||
* 3. 依次尝试不同的测试方法,直到连接成功
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = Application.class)
|
||||
public class OpcDaConnectionTest {
|
||||
|
||||
@Autowired
|
||||
private OpcDaProtocolDriverImpl opcDaProtocolDriver;
|
||||
|
||||
/**
|
||||
* 方案 1:空用户名和密码(本地连接最简单)
|
||||
* 适用场景:本地测试,DCOM 配置为允许匿名访问
|
||||
*/
|
||||
@Test
|
||||
public void testWithEmptyCredentials() {
|
||||
System.out.println("\n========================================");
|
||||
System.out.println("测试方案 1:空用户名和密码");
|
||||
System.out.println("========================================");
|
||||
|
||||
testConnection("", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 方案 2:使用当前 Java 进程用户
|
||||
* 适用场景:使用当前登录的 Windows 用户
|
||||
* 注意:需要输入正确的 Windows 密码
|
||||
*/
|
||||
@Test
|
||||
public void testWithCurrentUser() {
|
||||
System.out.println("\n========================================");
|
||||
System.out.println("测试方案 2:当前用户");
|
||||
System.out.println("========================================");
|
||||
|
||||
String currentUser = System.getProperty("user.name");
|
||||
System.out.println("当前用户: " + currentUser);
|
||||
System.out.println("请在代码中填入该用户的 Windows 密码!");
|
||||
|
||||
// TODO: 替换为你的 Windows 密码
|
||||
String password = "YOUR_PASSWORD_HERE";
|
||||
|
||||
if ("YOUR_PASSWORD_HERE".equals(password)) {
|
||||
System.err.println("错误:请先在代码中设置正确的密码!");
|
||||
return;
|
||||
}
|
||||
|
||||
testConnection(currentUser, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* 方案 3:使用 计算机名\用户名 格式
|
||||
* 适用场景:明确指定本地计算机的用户
|
||||
*/
|
||||
@Test
|
||||
public void testWithComputerNameUser() {
|
||||
System.out.println("\n========================================");
|
||||
System.out.println("测试方案 3:计算机名\\用户名");
|
||||
System.out.println("========================================");
|
||||
|
||||
String computerName = System.getenv("COMPUTERNAME");
|
||||
String userName = System.getProperty("user.name");
|
||||
String fullUserName = computerName + "\\" + userName;
|
||||
|
||||
System.out.println("计算机名: " + computerName);
|
||||
System.out.println("用户名: " + userName);
|
||||
System.out.println("完整用户名: " + fullUserName);
|
||||
System.out.println("请在代码中填入该用户的 Windows 密码!");
|
||||
|
||||
// TODO: 替换为你的 Windows 密码
|
||||
String password = "YOUR_PASSWORD_HERE";
|
||||
|
||||
if ("YOUR_PASSWORD_HERE".equals(password)) {
|
||||
System.err.println("错误:请先在代码中设置正确的密码!");
|
||||
return;
|
||||
}
|
||||
|
||||
testConnection(fullUserName, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* 方案 4:使用 Administrator 账户
|
||||
* 适用场景:使用管理员账户
|
||||
* 注意:确保 Administrator 账户已启用
|
||||
*/
|
||||
@Test
|
||||
public void testWithAdministrator() {
|
||||
System.out.println("\n========================================");
|
||||
System.out.println("测试方案 4:Administrator 账户");
|
||||
System.out.println("========================================");
|
||||
|
||||
System.out.println("注意:确保 Administrator 账户已启用");
|
||||
System.out.println("启用命令:net user Administrator /active:yes");
|
||||
System.out.println("请在代码中填入 Administrator 的密码!");
|
||||
|
||||
// TODO: 替换为 Administrator 的密码
|
||||
String password = "YOUR_ADMIN_PASSWORD_HERE";
|
||||
|
||||
if ("YOUR_ADMIN_PASSWORD_HERE".equals(password)) {
|
||||
System.err.println("错误:请先在代码中设置 Administrator 的密码!");
|
||||
return;
|
||||
}
|
||||
|
||||
testConnection("Administrator", password);
|
||||
}
|
||||
|
||||
/**
|
||||
* 方案 5:使用 .\用户名 格式(本地用户)
|
||||
* 适用场景:明确指定本地用户
|
||||
*/
|
||||
@Test
|
||||
public void testWithDotUser() {
|
||||
System.out.println("\n========================================");
|
||||
System.out.println("测试方案 5:.\\用户名 格式");
|
||||
System.out.println("========================================");
|
||||
|
||||
String userName = System.getProperty("user.name");
|
||||
String fullUserName = ".\\" + userName;
|
||||
|
||||
System.out.println("用户名: " + fullUserName);
|
||||
System.out.println("请在代码中填入该用户的 Windows 密码!");
|
||||
|
||||
// TODO: 替换为你的 Windows 密码
|
||||
String password = "YOUR_PASSWORD_HERE";
|
||||
|
||||
if ("YOUR_PASSWORD_HERE".equals(password)) {
|
||||
System.err.println("错误:请先在代码中设置正确的密码!");
|
||||
return;
|
||||
}
|
||||
|
||||
testConnection(fullUserName, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* 核心测试方法
|
||||
*/
|
||||
private void testConnection(String username, String password) {
|
||||
opcDaProtocolDriver.initial();
|
||||
|
||||
Map<String, AttributeBO> driverConfig = new HashMap<>();
|
||||
driverConfig.put("host", AttributeBO.builder().value("127.0.0.1").build());
|
||||
driverConfig.put("clsId", AttributeBO.builder().value("F8582CF2-88FB-11D0-B850-00C0F0104305").build());
|
||||
driverConfig.put("username", AttributeBO.builder().value(username).build());
|
||||
driverConfig.put("password", AttributeBO.builder().value(password).build());
|
||||
|
||||
Map<String, AttributeBO> pointConfig = new HashMap<>();
|
||||
pointConfig.put("group", AttributeBO.builder().value("Group0").build());
|
||||
pointConfig.put("tag", AttributeBO.builder().value("Random.Int1").build());
|
||||
|
||||
IotConnect connect = IotConnect.builder()
|
||||
.id(1)
|
||||
.code("OPC_DA_TEST")
|
||||
.host("127.0.0.1")
|
||||
.protocol("opc-da")
|
||||
.enabled(true)
|
||||
.description("OPC DA 连接测试")
|
||||
.build();
|
||||
|
||||
IotConfig config = IotConfig.builder()
|
||||
.id(1)
|
||||
.connectId(1)
|
||||
.alias("test_sensor")
|
||||
.aliasName("测试传感器")
|
||||
.registerAddress("Random.Int1")
|
||||
.dataType("int")
|
||||
.readonly(true)
|
||||
.enabled(true)
|
||||
.description("OPC DA 测试点位")
|
||||
.build();
|
||||
|
||||
try {
|
||||
System.out.println("\n--- 连接参数 ---");
|
||||
System.out.println("主机: " + driverConfig.get("host").getValue());
|
||||
System.out.println("CLSID: " + driverConfig.get("clsid").getValue());
|
||||
System.out.println("用户名: " + (username.isEmpty() ? "(空)" : username));
|
||||
System.out.println("密码: " + (password.isEmpty() ? "(空)" : "******"));
|
||||
System.out.println("组名: " + pointConfig.get("group").getValue());
|
||||
System.out.println("标签: " + pointConfig.get("tag").getValue());
|
||||
|
||||
System.out.println("\n正在连接...");
|
||||
RValue result = opcDaProtocolDriver.read(driverConfig, pointConfig, connect, config);
|
||||
|
||||
if (result != null) {
|
||||
System.out.println("\n✅ 连接成功!");
|
||||
System.out.println("读取值: " + result.getValue());
|
||||
System.out.println("\n========================================");
|
||||
System.out.println("成功配置:");
|
||||
System.out.println("用户名: " + username);
|
||||
System.out.println("请在正式代码中使用此配置!");
|
||||
System.out.println("========================================");
|
||||
} else {
|
||||
System.err.println("\n❌ 连接失败:返回结果为 null");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("\n❌ 连接失败");
|
||||
System.err.println("错误信息: " + e.getMessage());
|
||||
|
||||
// 分析错误并给出建议
|
||||
String errorMsg = e.getMessage();
|
||||
if (errorMsg != null) {
|
||||
if (errorMsg.contains("0x00000005") || errorMsg.contains("Access is denied")) {
|
||||
System.err.println("\n可能原因:");
|
||||
System.err.println("1. 用户名或密码错误");
|
||||
System.err.println("2. DCOM 权限未正确配置");
|
||||
System.err.println("3. 用户未在 'Distributed COM Users' 组中");
|
||||
System.err.println("\n建议:");
|
||||
System.err.println("- 检查密码是否正确");
|
||||
System.err.println("- 运行 dcomcnfg 配置权限");
|
||||
System.err.println("- 参考 OPC_DA_DCOM_完整配置指南.md");
|
||||
} else if (errorMsg.contains("0x00000533")) {
|
||||
System.err.println("\n可能原因:");
|
||||
System.err.println("- 用户账户被禁用");
|
||||
System.err.println("\n建议:");
|
||||
System.err.println("- 运行: net user " + username + " /active:yes");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示系统信息
|
||||
*/
|
||||
@Test
|
||||
public void showSystemInfo() {
|
||||
System.out.println("\n========================================");
|
||||
System.out.println("系统信息");
|
||||
System.out.println("========================================");
|
||||
System.out.println("计算机名: " + System.getenv("COMPUTERNAME"));
|
||||
System.out.println("当前用户: " + System.getProperty("user.name"));
|
||||
System.out.println("用户主目录: " + System.getProperty("user.home"));
|
||||
System.out.println("操作系统: " + System.getProperty("os.name"));
|
||||
System.out.println("========================================");
|
||||
System.out.println("\n建议测试顺序:");
|
||||
System.out.println("1. testWithEmptyCredentials() - 最简单");
|
||||
System.out.println("2. testWithCurrentUser() - 使用当前用户");
|
||||
System.out.println("3. testWithComputerNameUser() - 完整格式");
|
||||
System.out.println("4. testWithAdministrator() - 管理员账户");
|
||||
System.out.println("5. testWithDotUser() - 本地用户格式");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user