java中使用openmuc j60870库实现IEC104协议的主从站
阅读数:253 评论数:0
跳转到新版页面分类
python/Java
正文
一、前置内容
1、openmuc帮助文档
https://www.openmuc.org/iec-60870-5-104/javadoc/
2、pom依赖包
<!-- 104协议 -->
<dependency>
<groupId>org.openmuc</groupId>
<artifactId>j60870</artifactId>
<version>1.6.4</version>
</dependency>
二、相关知识点
1、遥测地址
// 发送包含多个浮点数的ASDU (短浮点数)
connection.send(new ASdu(
ASduType.M_ME_NC_1, // ASDU类型为浮点数
true,
CauseOfTransmission.INTERROGATED_BY_STATION,
false,
false,
0,
aSdu.getCommonAddress(),
new InformationObject[] {
new InformationObject(1, new InformationElement[][] {
{ new IeShortFloat(123.45f), new IeQuality(false, false, false, false, false) }
}),
// ... 添加更多的 InformationObject 以发送更多的浮点数
}
));
// 发送包含多个整数的ASDU (标度化值)
connection.send(new ASdu(
ASduType.M_ME_NB_1, // ASDU类型为标度化值
true,
CauseOfTransmission.INTERROGATED_BY_STATION,
false,
false,
0,
aSdu.getCommonAddress(),
new InformationObject[] {
new InformationObject(2, new InformationElement[][] {
{ new IeScaledValue(-32768), new IeQuality(false, false, false, false, false) },
{ new IeScaledValue(10), new IeQuality(false, false, false, false, false) }
}),
// ... 添加更多的 InformationObject 以发送更多的整数
}
));
请注意,每个InformationObject
通常对应于一个遥测地址。
遥测地址(也称为信息对象地址)是用来唯一标识子站中的每个数据点的。每个InformationObject
实例都有一个关联的地址,这个地址在ASDU中的所有信息对象中应该是唯一的,以便主站可以区分来自子站的不同测量值、状态或计数器。
如果所有的数据都来自同一个子站,它们的公共地址(Common Address)通常是相同的,因为公共地址用于标识整个子站或者逻辑设备。然而,即使这些数据点来自同一个子站,它们的遥测地址也应该是不同的,因为你需要区分子站内部的不同数据点。
例如,假设一个子站有多个传感器,每个传感器测量不同的物理量(如温度、压力、湿度等),那么即使这些传感器都在同一个子站内,每个传感器的读数都应该有一个独特的遥测地址。这样,当主站收到数据时,它可以通过遥测地址知道每个数据点对应于子站中的哪个传感器。
这里是一个简化的例子:
- 子站A的公共地址:1
- 温度传感器的遥测地址:101
- 压力传感器的遥测地址:102
- 湿度传感器的遥测地址:103
2、IeQuality
IeQuality
类表示信息元素的质量描述符。质量描述符提供了有关遥测或遥信数据质量的附加信息,这对于评估数据的可靠性和采取相应的控制或显示措施至关重要。
IeQuality
的构造函数通常接受几个布尔参数,每个参数代表了质量描述符的一个特定方面。以下是这些参数的典型含义:
- 无效 (Invalid):数据是否有效。如果为
true
,则表示这个信息元素的值不可信。 - 未使用 (Not Used):这个参数在标准中保留,通常不使用。
- 溢出 (Overflow):是否发生了溢出。如果为
true
,则表示测量值超出了可表示的范围。 - 被取代 (Substituted):数据是否被取代。如果为
true
,则表示这个值是由自动装置以外的设备或手动输入的。 - 非当前值 (Non-topical):数据是否为非当前值。如果为
true
,则表示这个值不是最新的测量值,而是过去的某个值。
一个正常的有效测量值可能会使用 new IeQuality(false, false, false, false, false)
。
3、一次发送多个InformationObject
// 假设您有一个包含多个遥测数据的List<TelemetryDTO> telemetryDTOs
List<TelemetryDTO> telemetryDTOs = ...;
// 创建一个InformationObject数组,大小为telemetryDTOs的大小
InformationObject[] informationObjects = new InformationObject[telemetryDTOs.size()];
// 填充InformationObject数组
for (int i = 0; i < telemetryDTOs.size(); i++) {
TelemetryDTO telemetryDTO = telemetryDTOs.get(i);
informationObjects[i] = new InformationObject(i + 1, new InformationElement[][]{
{
new IeScaledValue(telemetryDTO.getOrder()),
new IeQuality(false, false, false, false, false),
new IeTime56(telemetryDTO.getDetectTime().getTime())
}
});
}
// 创建ASdu并包含所有的InformationObject
ASdu aSdu = new ASdu(
ASduType.M_ME_TE_1,
true,
CauseOfTransmission.INTERROGATED_BY_STATION,
false,
false,
0,
commonAddress, // 确保这是正确的公共地址
informationObjects
);
// 发送ASdu
try {
connection.send(aSdu);
System.out.println("Sent ASDU with multiple InformationObjects.");
} catch (IOException e) {
System.err.println("Failed to send ASDU: " + e.getMessage());
}
4、ASdu
// 创建ASdu时指定originatorAddress和commonAddress
ASdu aSdu = new ASdu(
ASduType.M_SP_TB_1, // 例如,带时间标签的单点信息ASDU类型
false, // f false then the ASDU contains a sequence of information
CauseOfTransmission.SPONTANEOUS, // 传输原因,这里是自发的
false, // 测试标志
false, // 负确认标志
originatorAddress, // 发起者地址,通常设置为0
commonAddress, // 公共地址,根据你的网络配置来设置
informationObjects // 包含信息对象的数组
);
// 发送ASdu
connection.send(aSdu);
(1)orginatorAddress
是用来标识发送ASDU的设备或者系统的地址。在很多实现中,这个字段通常被设置为0,因为在点对点连接中,通信的发起者是已知的。然而,在一些特定的应用场景中,特别是在网络可能包含多个控制中心或者主站的情况下,originatorAddress
可能会被用来指定发送命令的主站。
(2)commonAddress
这通常是指定给子站的地址。
5、布尔值的上报
在IEC 60870-5-104协议中,布尔值通常通过遥信(Telesignalisation)信息对象来上报。遥信用于表示开关量,例如设备的开/关状态,这些状态可以用布尔值表示。以下是一些常用的信息对象类型,用于上报布尔值:
(1)M_SP_NA_1 (单点信息) - 这是最简单的类型,用于上报单个布尔值,例如一个开关的状态。每个信息元素代表一个二进制状态,通常用于表示开或关。
(2)M_DP_NA_1 (双点信息) - 这个类型用于上报包含两种稳态的布尔值,例如一个断路器的状态,它可以是开、关或不确定。
对于单点信息,布尔值通常是这样表示的:
0
表示OFF
或逻辑FALSE
1
表示ON
或逻辑TRUE
// 创建一个InformationObject数组,包含一个单点信息对象
InformationObject[] informationObjects = new InformationObject[]{
new InformationObject(
objectAddress, // 信息对象地址
new InformationElement[][]{
{
new IeSinglePointWithQuality(
booleanValue, // 布尔值
false, // 不带时标
false, // 不带品质描述符
false, // 非当前值
false // 非被取代的值
)
}
}
)
};
// 创建ASdu并包含信息对象
ASdu aSdu = new ASdu(
ASduType.M_SP_NA_1, // 单点信息类型
false, // 是否需要确认
CauseOfTransmission.SPONTANEOUS, // 传输原因
false, // 测试标志
false, // 负确认标志
0, // 发起者地址,通常设置为0
commonAddress, // 公共地址
informationObjects // 包含信息对象的数组
);
// 发送ASdu
connection.send(aSdu);