1、电表和modbus设备控制完成
parent
5fed47a2c8
commit
94b39b4f6d
|
@ -16,4 +16,6 @@ public class TcpClientConfig {
|
||||||
private String host;
|
private String host;
|
||||||
|
|
||||||
private int port;
|
private int port;
|
||||||
|
|
||||||
|
private int interval;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package cc.iotkit.plugins.dlt645.service;
|
package cc.iotkit.plugins.dlt645.service;
|
||||||
|
|
||||||
import cc.iotkit.common.utils.JsonUtils;
|
|
||||||
import cc.iotkit.plugin.core.thing.IThingService;
|
import cc.iotkit.plugin.core.thing.IThingService;
|
||||||
import cc.iotkit.plugin.core.thing.actions.DeviceState;
|
import cc.iotkit.plugin.core.thing.actions.DeviceState;
|
||||||
import cc.iotkit.plugin.core.thing.actions.IDeviceAction;
|
import cc.iotkit.plugin.core.thing.actions.IDeviceAction;
|
||||||
|
@ -57,6 +56,8 @@ public class TcpClientVerticle extends AbstractVerticle {
|
||||||
|
|
||||||
private int connectState = 0;
|
private int connectState = 0;
|
||||||
|
|
||||||
|
private long timerID;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start() {
|
public void start() {
|
||||||
log.info("init start");
|
log.info("init start");
|
||||||
|
@ -74,10 +75,8 @@ public class TcpClientVerticle extends AbstractVerticle {
|
||||||
options.setReconnectAttempts(Integer.MAX_VALUE);
|
options.setReconnectAttempts(Integer.MAX_VALUE);
|
||||||
options.setReconnectInterval(20000L);
|
options.setReconnectInterval(20000L);
|
||||||
netClient = vertx.createNetClient(options);
|
netClient = vertx.createNetClient(options);
|
||||||
log.info("start1 connect->" + config.getHost() + ":" + config.getPort());
|
|
||||||
netClient.connect(config.getPort(), config.getHost())
|
netClient.connect(config.getPort(), config.getHost())
|
||||||
.onComplete(result -> {
|
.onComplete(result -> {
|
||||||
System.out.println("connect result:" + JsonUtils.toJsonString(result));
|
|
||||||
if (result.succeeded()) {
|
if (result.succeeded()) {
|
||||||
connectState = 2;
|
connectState = 2;
|
||||||
log.info("connect dlt645 server success");
|
log.info("connect dlt645 server success");
|
||||||
|
@ -91,7 +90,7 @@ public class TcpClientVerticle extends AbstractVerticle {
|
||||||
Object func = ret.get(DLT645Analysis.FUN);
|
Object func = ret.get(DLT645Analysis.FUN);
|
||||||
DLT645FunCode funCode = DLT645FunCode.decodeEntity((byte) func);
|
DLT645FunCode funCode = DLT645FunCode.decodeEntity((byte) func);
|
||||||
if (funCode.isError()) {
|
if (funCode.isError()) {
|
||||||
log.error("message erroe:{}", hexStr);
|
log.info("message erroe:{}", hexStr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//获取设备地址
|
//获取设备地址
|
||||||
|
@ -100,26 +99,31 @@ public class TcpClientVerticle extends AbstractVerticle {
|
||||||
ByteUtils.byteInvertedOrder(adrrTmp, addr);
|
ByteUtils.byteInvertedOrder(adrrTmp, addr);
|
||||||
//获取数据
|
//获取数据
|
||||||
byte[] dat = (byte[]) ret.get(DLT645Analysis.DAT);
|
byte[] dat = (byte[]) ret.get(DLT645Analysis.DAT);
|
||||||
|
String strAddr=ByteUtils.byteArrayToHexString(addr,false);
|
||||||
DLT645V2007Data dataEntity = new DLT645V2007Data();
|
DLT645V2007Data dataEntity = new DLT645V2007Data();
|
||||||
dataEntity.decodeValue(dat, DLT645Analysis.din2entity);
|
dataEntity.decodeValue(dat, DLT645Analysis.din2entity);
|
||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.put("p" + dataEntity.getKey(), dataEntity.getValue());//数据标识
|
params.put("p" + dataEntity.getKey(), dataEntity.getValue());//数据标识
|
||||||
thingService.post(pluginInfo.getPluginId(),
|
thingService.post(pluginInfo.getPluginId(),
|
||||||
applyPkDn(PropertyReport.builder()
|
PropertyReport.builder().deviceName(strAddr).productKey("PwMfpXmp4ZWkGahn")
|
||||||
.params(params)
|
.params(params)
|
||||||
.build()
|
.build()
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}).closeHandler(res -> {
|
}).closeHandler(res -> {
|
||||||
connectState = 0;
|
connectState = 0;
|
||||||
|
vertx.cancelTimer(timerID);
|
||||||
log.info("dlt645 tcp connection closed!");
|
log.info("dlt645 tcp connection closed!");
|
||||||
stateChange(DeviceState.OFFLINE);
|
stateChange(DeviceState.OFFLINE);
|
||||||
}
|
}
|
||||||
).exceptionHandler(res -> {
|
).exceptionHandler(res -> {
|
||||||
connectState = 0;
|
connectState = 0;
|
||||||
|
vertx.cancelTimer(timerID);
|
||||||
log.info("dlt645 tcp connection exce!");
|
log.info("dlt645 tcp connection exce!");
|
||||||
stateChange(DeviceState.OFFLINE);
|
stateChange(DeviceState.OFFLINE);
|
||||||
});
|
});
|
||||||
|
timerID = vertx.setPeriodic(config.getInterval(), t -> {
|
||||||
|
readDataTask();
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
connectState = 0;
|
connectState = 0;
|
||||||
log.info("connect dlt645 tcp error", result.cause());
|
log.info("connect dlt645 tcp error", result.cause());
|
||||||
|
@ -132,7 +136,6 @@ public class TcpClientVerticle extends AbstractVerticle {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Scheduled(initialDelay = 5, fixedRate = 60, timeUnit = TimeUnit.SECONDS)
|
|
||||||
private void readDataTask() {
|
private void readDataTask() {
|
||||||
log.info("readData:" + socket);
|
log.info("readData:" + socket);
|
||||||
if (socket != null) {
|
if (socket != null) {
|
||||||
|
@ -146,6 +149,8 @@ public class TcpClientVerticle extends AbstractVerticle {
|
||||||
if (netClient != null) {
|
if (netClient != null) {
|
||||||
netClient.close();
|
netClient.close();
|
||||||
}
|
}
|
||||||
|
vertx.cancelTimer(timerID);
|
||||||
|
connectState = 0;
|
||||||
super.stop();
|
super.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +165,7 @@ public class TcpClientVerticle extends AbstractVerticle {
|
||||||
|
|
||||||
private IDeviceAction applyPkDn(IDeviceAction action) {
|
private IDeviceAction applyPkDn(IDeviceAction action) {
|
||||||
action.setProductKey("BRD3x4fkKxkaxXFt");
|
action.setProductKey("BRD3x4fkKxkaxXFt");
|
||||||
action.setDeviceName("123456789123");
|
action.setDeviceName("WG123456");
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,5 +3,6 @@ plugin:
|
||||||
mainPackage: cc.iotkit.plugin
|
mainPackage: cc.iotkit.plugin
|
||||||
|
|
||||||
tcp:
|
tcp:
|
||||||
host: xxx
|
host: 25on621889.goho.co
|
||||||
port: 43161
|
port: 43161
|
||||||
|
interval: 10000
|
||||||
|
|
|
@ -3,14 +3,21 @@
|
||||||
"id": "host",
|
"id": "host",
|
||||||
"name": "服务端ip",
|
"name": "服务端ip",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"value": "0.0.0.0",
|
"value": "25on621889.goho.co",
|
||||||
"desc": "服务端ip"
|
"desc": "服务端ip"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "port",
|
"id": "port",
|
||||||
"name": "服务端端口",
|
"name": "服务端端口",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"value": 1111,
|
"value": 43161,
|
||||||
"desc": "服务端端口"
|
"desc": "服务端端口"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "interval",
|
||||||
|
"name": "采集频率",
|
||||||
|
"type": "number",
|
||||||
|
"value": 10000,
|
||||||
|
"desc": "采集频率"
|
||||||
}
|
}
|
||||||
]
|
]
|
|
@ -0,0 +1,64 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>iot-iita-plugins</artifactId>
|
||||||
|
<groupId>cc.iotkit.plugins</groupId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>hydrovalve-plugin</artifactId>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>dev</id>
|
||||||
|
<activation>
|
||||||
|
<activeByDefault>true</activeByDefault>
|
||||||
|
</activation>
|
||||||
|
<properties>
|
||||||
|
<plugin.build.mode>dev</plugin.build.mode>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
<id>prod</id>
|
||||||
|
<properties>
|
||||||
|
<plugin.build.mode>prod</plugin.build.mode>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.gitee.starblues</groupId>
|
||||||
|
<artifactId>spring-brick-maven-packager</artifactId>
|
||||||
|
<version>${spring-brick-package.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<mode>${plugin.build.mode}</mode>
|
||||||
|
<pluginInfo>
|
||||||
|
<id>hydrovalve-plugin</id>
|
||||||
|
<bootstrapClass>cc.iotkit.plugins.hydrovalve.Application</bootstrapClass>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<provider>iita</provider>
|
||||||
|
<description>modbus插件</description>
|
||||||
|
<configFileName>application.yml</configFileName>
|
||||||
|
</pluginInfo>
|
||||||
|
<prodConfig>
|
||||||
|
<packageType>jar</packageType>
|
||||||
|
</prodConfig>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>repackage</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,22 @@
|
||||||
|
package cc.iotkit.plugins.hydrovalve;
|
||||||
|
|
||||||
|
import com.gitee.starblues.bootstrap.SpringPluginBootstrap;
|
||||||
|
import com.gitee.starblues.bootstrap.annotation.OneselfConfig;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author:tfd
|
||||||
|
* @Date:2024/1/8 14:57
|
||||||
|
*/
|
||||||
|
@SpringBootApplication(scanBasePackages = {"cc.iotkit.plugin.core", "cc.iotkit.plugins.hydrovalve"})
|
||||||
|
@OneselfConfig(mainConfigFileName = {"application.yml"})
|
||||||
|
@EnableConfigurationProperties
|
||||||
|
@EnableScheduling
|
||||||
|
public class Application extends SpringPluginBootstrap {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
new Application().run(Application.class, args);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package cc.iotkit.plugins.hydrovalve.analysis;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author:tfd
|
||||||
|
* @Date:2024/1/9 15:41
|
||||||
|
*/
|
||||||
|
public abstract class ModBusAnalysis {
|
||||||
|
/**
|
||||||
|
* 编码:将实体打包成报文
|
||||||
|
*
|
||||||
|
* @param entity 实体
|
||||||
|
* @return 数据报文
|
||||||
|
*/
|
||||||
|
public abstract byte[] packCmd4Entity(ModBusEntity entity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解包:将报文解码成实体
|
||||||
|
*
|
||||||
|
* @param arrCmd 报文
|
||||||
|
* @return 实体
|
||||||
|
*/
|
||||||
|
public abstract ModBusEntity unPackCmd2Entity(byte[] arrCmd);
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package cc.iotkit.plugins.hydrovalve.analysis;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author:tfd
|
||||||
|
* @Date:2024/1/9 15:45
|
||||||
|
*/
|
||||||
|
public class ModBusConstants {
|
||||||
|
public static final String MODE = "modbusMode";
|
||||||
|
public static final String MODE_ASCII = "ASCII";
|
||||||
|
public static final String MODE_RTU = "RTU";
|
||||||
|
public static final String MODE_TCP = "TCP";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ModBus的报文结构
|
||||||
|
*/
|
||||||
|
public static final String SN = "sn";
|
||||||
|
public static final String ADDR = "devAddr";
|
||||||
|
public static final String FUNC = "func";
|
||||||
|
public static final String DATA = "data";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 寄存器地址和数量
|
||||||
|
*/
|
||||||
|
public static final String REG_ADDR = "regAddr";
|
||||||
|
public static final String REG_CNT = "regCnt";
|
||||||
|
|
||||||
|
public static final String REG_HOLD_STATUS = "regHoldStatus";
|
||||||
|
|
||||||
|
//读多个保持寄存器
|
||||||
|
public static final byte FUN_CODE3 = 0x03;
|
||||||
|
|
||||||
|
//写单个保持寄存器
|
||||||
|
public static final byte FUN_CODE6 = 0x06;
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package cc.iotkit.plugins.hydrovalve.analysis;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author:tfd
|
||||||
|
* @Date:2024/1/9 15:44
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class ModBusEntity {
|
||||||
|
/**
|
||||||
|
* 流水号
|
||||||
|
*/
|
||||||
|
private int sn = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 地址
|
||||||
|
*/
|
||||||
|
private byte devAddr = 0x01;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 功能码
|
||||||
|
*/
|
||||||
|
private byte func = 0x01;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据域
|
||||||
|
*/
|
||||||
|
private byte[] data = new byte[0];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 出错信息
|
||||||
|
*/
|
||||||
|
private int errCode = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 出错信息
|
||||||
|
*/
|
||||||
|
private String errMsg = "";
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package cc.iotkit.plugins.hydrovalve.analysis;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author:tfd
|
||||||
|
* @Date:2024/1/9 15:48
|
||||||
|
*/
|
||||||
|
public class ModBusError {
|
||||||
|
static final String err01 = "err=01:非法的功能码";
|
||||||
|
static final String err02 = "err=02:非法的数据地址";
|
||||||
|
static final String err03 = "err=03:非法的数据值";
|
||||||
|
static final String err04 = "err=04:服务器故障";
|
||||||
|
static final String err05 = "err=05:确认。";
|
||||||
|
static final String err06 = "err=06:服务器繁忙";
|
||||||
|
static final String err10 = "err=10:网关故障:网关路经是无效的";
|
||||||
|
static final String err11 = "err=11:网关故障:目标设备没有响应";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取出错信息
|
||||||
|
* @param code 出错代码
|
||||||
|
* @return 出错信息
|
||||||
|
*/
|
||||||
|
static String getError(int code) {
|
||||||
|
if (code == 1) {
|
||||||
|
return err01;
|
||||||
|
}
|
||||||
|
if (code == 2) {
|
||||||
|
return err02;
|
||||||
|
}
|
||||||
|
if (code == 3) {
|
||||||
|
return err03;
|
||||||
|
}
|
||||||
|
if (code == 4) {
|
||||||
|
return err04;
|
||||||
|
}
|
||||||
|
if (code == 5) {
|
||||||
|
return err05;
|
||||||
|
}
|
||||||
|
if (code == 6) {
|
||||||
|
return err06;
|
||||||
|
}
|
||||||
|
if (code == 10) {
|
||||||
|
return err10;
|
||||||
|
}
|
||||||
|
if (code == 11) {
|
||||||
|
return err11;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,171 @@
|
||||||
|
package cc.iotkit.plugins.hydrovalve.analysis;
|
||||||
|
|
||||||
|
import cc.iotkit.common.utils.StringUtils;
|
||||||
|
import cc.iotkit.plugins.hydrovalve.utils.ByteUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author:tfd
|
||||||
|
* @Date:2024/1/9 15:53
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class ModBusRtuAnalysis extends ModBusAnalysis {
|
||||||
|
/**
|
||||||
|
* 校验CRC16
|
||||||
|
*
|
||||||
|
* @param arrCmd
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static int getCRC16(byte[] arrCmd) {
|
||||||
|
int iSize = arrCmd.length - 2;
|
||||||
|
|
||||||
|
// 检查:帧长度
|
||||||
|
if (iSize < 2) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wCrcMathematics = 0xA001;
|
||||||
|
|
||||||
|
int usCrc16 = 0x00;
|
||||||
|
|
||||||
|
//16位的CRC寄存器
|
||||||
|
int byteCrc16Lo = 0xFF;
|
||||||
|
int byteCrc16Hi = 0xFF;
|
||||||
|
//临时变量
|
||||||
|
int byteSaveHi = 0x00;
|
||||||
|
int byteSaveLo = 0x00;
|
||||||
|
|
||||||
|
//CRC多项式码的寄存器
|
||||||
|
int byteCl = wCrcMathematics % 0x100;
|
||||||
|
int byteCh = wCrcMathematics / 0x100;
|
||||||
|
|
||||||
|
for (int i = 0; i < iSize; i++) {
|
||||||
|
byteCrc16Lo &= 0xFF;
|
||||||
|
byteCrc16Hi &= 0xFF;
|
||||||
|
byteSaveHi &= 0xFF;
|
||||||
|
byteSaveLo &= 0xFF;
|
||||||
|
|
||||||
|
byteCrc16Lo ^= arrCmd[i]; //每一个数据与CRC寄存器进行异或
|
||||||
|
for (int k = 0; k < 8; k++) {
|
||||||
|
byteCrc16Lo &= 0xFF;
|
||||||
|
byteCrc16Hi &= 0xFF;
|
||||||
|
|
||||||
|
byteSaveHi = byteCrc16Hi;
|
||||||
|
byteSaveLo = byteCrc16Lo;
|
||||||
|
byteCrc16Hi /= 2; //高位右移一位
|
||||||
|
byteCrc16Lo /= 2; //低位右移一位
|
||||||
|
if ((byteSaveHi & 0x01) == 0x01) //如果高位字节最后一位为1
|
||||||
|
{
|
||||||
|
byteCrc16Lo |= 0x80; //则低位字节右移后前面补1
|
||||||
|
} //否则自动补0
|
||||||
|
if ((byteSaveLo & 0x01) == 0x01) //如果高位字节最后一位为1,则与多项式码进行异或
|
||||||
|
{
|
||||||
|
byteCrc16Hi ^= byteCh;
|
||||||
|
byteCrc16Lo ^= byteCl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
usCrc16 = (byteCrc16Hi & 0xff) * 0x100 + (byteCrc16Lo & 0xff);
|
||||||
|
|
||||||
|
return usCrc16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解码
|
||||||
|
*
|
||||||
|
* @param arrCmd 报文
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ModBusEntity unPackCmd2Entity(byte[] arrCmd) {
|
||||||
|
ModBusEntity entity = new ModBusEntity();
|
||||||
|
|
||||||
|
int iSize = arrCmd.length;
|
||||||
|
if (iSize < 4) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 地址码
|
||||||
|
byte byAddr = arrCmd[0];
|
||||||
|
entity.setDevAddr(byAddr);
|
||||||
|
|
||||||
|
// 功能码
|
||||||
|
byte byFun = arrCmd[1];
|
||||||
|
entity.setFunc(byFun);
|
||||||
|
|
||||||
|
// 数据域
|
||||||
|
int iDataSize = iSize - 4;
|
||||||
|
entity.setData(new byte[iDataSize]);
|
||||||
|
byte[] arrData = entity.getData();
|
||||||
|
System.arraycopy(arrCmd, 2, arrData, 0, iDataSize);
|
||||||
|
|
||||||
|
// 校验CRC
|
||||||
|
int wCrc16OK = getCRC16(arrCmd);
|
||||||
|
byte crcH = (byte) (wCrc16OK & 0xff);
|
||||||
|
byte crcL = (byte) ((wCrc16OK & 0xff00) >> 8);
|
||||||
|
if (arrCmd[arrCmd.length - 1] == crcL && arrCmd[arrCmd.length - 2] == crcH) {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编码
|
||||||
|
*
|
||||||
|
* @return 编码是否成功
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public byte[] packCmd4Entity(ModBusEntity entity) {
|
||||||
|
int iSize = entity.getData().length;
|
||||||
|
|
||||||
|
byte[] arrCmd = new byte[iSize + 4];
|
||||||
|
|
||||||
|
// 地址码
|
||||||
|
arrCmd[0] = entity.getDevAddr();
|
||||||
|
|
||||||
|
// 功能码
|
||||||
|
arrCmd[1] = entity.getFunc();
|
||||||
|
|
||||||
|
// 数据域
|
||||||
|
System.arraycopy(entity.getData(), 0, arrCmd, 2, iSize);
|
||||||
|
|
||||||
|
// 校验CRC
|
||||||
|
int wCrc16 = getCRC16(arrCmd);
|
||||||
|
arrCmd[arrCmd.length - 2] = (byte) (wCrc16 % 0x100);
|
||||||
|
arrCmd[arrCmd.length - 1] = (byte) (wCrc16 / 0x100);
|
||||||
|
|
||||||
|
return arrCmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// String hexString = "0103020457FB7A";
|
||||||
|
String hexString = "01060001000119CA";
|
||||||
|
ModBusRtuAnalysis a=new ModBusRtuAnalysis();
|
||||||
|
ModBusEntity b=a.unPackCmd2Entity(ByteUtils.hexStrToBinaryStr(hexString));
|
||||||
|
int lenth=b.getData()[0];
|
||||||
|
byte[] val = new byte[lenth];
|
||||||
|
System.arraycopy(b.getData(), 1, val, 0, lenth);
|
||||||
|
log.info("ret:"+Integer.parseInt(ByteUtils.BinaryToHexString(val,false), 16));
|
||||||
|
ModBusEntity c=new ModBusEntity();
|
||||||
|
c.setDevAddr((byte) 1);
|
||||||
|
c.setFunc(ModBusConstants.FUN_CODE3);
|
||||||
|
Integer dz=0;
|
||||||
|
Integer dzsl=10;
|
||||||
|
String a1=StringUtils.leftPad(dz.toHexString(dz),4,'0')+StringUtils.leftPad(dz.toHexString(dzsl),4,'0');
|
||||||
|
c.setData(ByteUtils.hexStrToBinaryStr(a1));
|
||||||
|
byte[] d=a.packCmd4Entity(c);
|
||||||
|
log.info("ret1:"+ByteUtils.BinaryToHexString(d,false));
|
||||||
|
ModBusEntity e=new ModBusEntity();
|
||||||
|
e.setDevAddr((byte) 1);
|
||||||
|
e.setFunc(ModBusConstants.FUN_CODE6);
|
||||||
|
Integer dze=0;
|
||||||
|
Integer dzsle=1;
|
||||||
|
String a1e=StringUtils.leftPad(dz.toHexString(dze),4,'0')+StringUtils.leftPad(dz.toHexString(dzsle),4,'0');
|
||||||
|
e.setData(ByteUtils.hexStrToBinaryStr(a1e));
|
||||||
|
byte[] f=a.packCmd4Entity(e);
|
||||||
|
log.info("rete:"+ByteUtils.BinaryToHexString(f,false));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package cc.iotkit.plugins.hydrovalve.conf;
|
||||||
|
|
||||||
|
import cc.iotkit.plugin.core.IPluginConfig;
|
||||||
|
import cc.iotkit.plugin.core.IPluginScript;
|
||||||
|
import cc.iotkit.plugin.core.LocalPluginConfig;
|
||||||
|
import cc.iotkit.plugin.core.LocalPluginScript;
|
||||||
|
import cc.iotkit.plugin.core.thing.IThingService;
|
||||||
|
import cc.iotkit.plugins.hydrovalve.service.FakeThingService;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author:tfd
|
||||||
|
* @Date:2024/1/8 14:58
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class BeanConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnProperty(name = "plugin.runMode", havingValue = "dev")
|
||||||
|
IThingService getThingService() {
|
||||||
|
return new FakeThingService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnProperty(name = "plugin.runMode", havingValue = "dev")
|
||||||
|
IPluginScript getPluginScript() {
|
||||||
|
return new LocalPluginScript("script.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnProperty(name = "plugin.runMode", havingValue = "dev")
|
||||||
|
IPluginConfig getPluginConfig(){
|
||||||
|
return new LocalPluginConfig();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package cc.iotkit.plugins.hydrovalve.conf;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author:tfd
|
||||||
|
* @Date:2024/1/8 15:04
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "hydrovalve")
|
||||||
|
public class HydrovalveConfig {
|
||||||
|
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
private int interval;
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package cc.iotkit.plugins.hydrovalve.service;
|
||||||
|
|
||||||
|
import cc.iotkit.model.device.DeviceInfo;
|
||||||
|
import cc.iotkit.model.product.Product;
|
||||||
|
import cc.iotkit.plugin.core.thing.IThingService;
|
||||||
|
import cc.iotkit.plugin.core.thing.actions.ActionResult;
|
||||||
|
import cc.iotkit.plugin.core.thing.actions.IDeviceAction;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author:tfd
|
||||||
|
* @Date:2024/1/8 14:58
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class FakeThingService implements IThingService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionResult post(String pluginId, IDeviceAction action) {
|
||||||
|
log.info("post action:{}", action);
|
||||||
|
return ActionResult.builder().code(0).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Product getProduct(String pk) {
|
||||||
|
return Product.builder()
|
||||||
|
.productKey("cGCrkK7Ex4FESAwe")
|
||||||
|
.productSecret("aaaaaaaa")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeviceInfo getDevice(String dn) {
|
||||||
|
return DeviceInfo.builder()
|
||||||
|
.productKey("cGCrkK7Ex4FESAwe")
|
||||||
|
.deviceName(dn)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, ?> getProperty(String dn) {
|
||||||
|
return new HashMap<>(0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package cc.iotkit.plugins.hydrovalve.service;
|
||||||
|
|
||||||
|
import cc.iotkit.common.utils.StringUtils;
|
||||||
|
import cc.iotkit.plugin.core.thing.IDevice;
|
||||||
|
import cc.iotkit.plugin.core.thing.actions.ActionResult;
|
||||||
|
import cc.iotkit.plugin.core.thing.actions.down.DeviceConfig;
|
||||||
|
import cc.iotkit.plugin.core.thing.actions.down.PropertyGet;
|
||||||
|
import cc.iotkit.plugin.core.thing.actions.down.PropertySet;
|
||||||
|
import cc.iotkit.plugin.core.thing.actions.down.ServiceInvoke;
|
||||||
|
import cc.iotkit.plugins.hydrovalve.analysis.ModBusConstants;
|
||||||
|
import cc.iotkit.plugins.hydrovalve.analysis.ModBusEntity;
|
||||||
|
import cc.iotkit.plugins.hydrovalve.analysis.ModBusRtuAnalysis;
|
||||||
|
import cc.iotkit.plugins.hydrovalve.utils.ByteUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author:tfd
|
||||||
|
* @Date:2024/1/10 11:06
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class ModBusDevice implements IDevice {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ModbusVerticle modbusVerticle;
|
||||||
|
|
||||||
|
ModBusRtuAnalysis analysis=new ModBusRtuAnalysis();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionResult config(DeviceConfig action) {
|
||||||
|
return ActionResult.builder().code(0).reason("").build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionResult propertyGet(PropertyGet action) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionResult propertySet(PropertySet action) {
|
||||||
|
ModBusEntity read=new ModBusEntity();
|
||||||
|
String devAddr=action.getDeviceName().split("_")[1];
|
||||||
|
read.setFunc(ModBusConstants.FUN_CODE6);
|
||||||
|
read.setDevAddr(Byte.parseByte(devAddr));
|
||||||
|
Integer addr=0;
|
||||||
|
for (Map.Entry<String, ?> entry : action.getParams().entrySet()) {
|
||||||
|
int val = Integer.parseInt((String) entry.getValue());
|
||||||
|
String a1= StringUtils.leftPad(addr.toHexString(addr),4,'0')+StringUtils.leftPad(addr.toHexString(val),4,'0');
|
||||||
|
read.setData(ByteUtils.hexStrToBinaryStr(a1));
|
||||||
|
byte[] msg = analysis.packCmd4Entity(read);
|
||||||
|
modbusVerticle.sendMsg(msg);
|
||||||
|
}
|
||||||
|
return ActionResult.builder().code(0).reason("success").build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionResult serviceInvoke(ServiceInvoke action) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
package cc.iotkit.plugins.hydrovalve.service;
|
||||||
|
|
||||||
|
import cc.iotkit.common.utils.JsonUtils;
|
||||||
|
import cc.iotkit.plugin.core.IPluginConfig;
|
||||||
|
import cc.iotkit.plugin.core.IPluginScript;
|
||||||
|
import cc.iotkit.plugin.core.thing.IThingService;
|
||||||
|
import cc.iotkit.plugins.hydrovalve.conf.HydrovalveConfig;
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
|
import cn.hutool.core.bean.copier.CopyOptions;
|
||||||
|
import com.gitee.starblues.bootstrap.annotation.AutowiredType;
|
||||||
|
import com.gitee.starblues.bootstrap.realize.PluginCloseListener;
|
||||||
|
import com.gitee.starblues.core.PluginCloseType;
|
||||||
|
import com.gitee.starblues.core.PluginInfo;
|
||||||
|
import io.vertx.core.Future;
|
||||||
|
import io.vertx.core.Vertx;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.support.GenericApplicationContext;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author:tfd
|
||||||
|
* @Date:2024/1/8 14:57
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class ModbusPlugin implements PluginCloseListener {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PluginInfo pluginInfo;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@AutowiredType(AutowiredType.Type.MAIN_PLUGIN)
|
||||||
|
private IPluginScript pluginScript;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@AutowiredType(AutowiredType.Type.MAIN_PLUGIN)
|
||||||
|
private IThingService thingService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@AutowiredType(AutowiredType.Type.MAIN_PLUGIN)
|
||||||
|
private IPluginConfig pluginConfig;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private HydrovalveConfig modbusConfig;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ModbusVerticle modbusVerticle;
|
||||||
|
|
||||||
|
private Vertx vertx;
|
||||||
|
private String deployedId;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init(){
|
||||||
|
vertx = Vertx.vertx();
|
||||||
|
try {
|
||||||
|
//获取插件最新配置替换当前配置
|
||||||
|
Map<String, Object> config = pluginConfig.getConfig(pluginInfo.getPluginId());
|
||||||
|
BeanUtil.copyProperties(config, modbusConfig, CopyOptions.create().ignoreNullValue());
|
||||||
|
modbusVerticle.setModbusConfig(modbusConfig);
|
||||||
|
|
||||||
|
Future<String> future = vertx.deployVerticle(modbusVerticle);
|
||||||
|
future.onSuccess((s -> {
|
||||||
|
deployedId = s;
|
||||||
|
log.info("modbus plugin started success,config:"+ JsonUtils.toJsonString(modbusConfig));
|
||||||
|
}));
|
||||||
|
future.onFailure(Throwable::printStackTrace);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error("modbus plugin error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
@Override
|
||||||
|
public void close(GenericApplicationContext applicationContext, PluginInfo pluginInfo, PluginCloseType closeType) {
|
||||||
|
log.info("plugin close,type:{},pluginId:{}", closeType, pluginInfo.getPluginId());
|
||||||
|
if (deployedId != null) {
|
||||||
|
CountDownLatch wait = new CountDownLatch(1);
|
||||||
|
Future<Void> future = vertx.undeploy(deployedId);
|
||||||
|
future.onSuccess(unused -> {
|
||||||
|
log.info("modbus plugin stopped success");
|
||||||
|
wait.countDown();
|
||||||
|
});
|
||||||
|
future.onFailure(h -> {
|
||||||
|
log.info("modbus plugin stopped failed");
|
||||||
|
h.printStackTrace();
|
||||||
|
wait.countDown();
|
||||||
|
});
|
||||||
|
wait.await(5, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,182 @@
|
||||||
|
package cc.iotkit.plugins.hydrovalve.service;
|
||||||
|
|
||||||
|
import cc.iotkit.common.utils.StringUtils;
|
||||||
|
import cc.iotkit.plugin.core.thing.IThingService;
|
||||||
|
import cc.iotkit.plugin.core.thing.actions.DeviceState;
|
||||||
|
import cc.iotkit.plugin.core.thing.actions.up.DeviceRegister;
|
||||||
|
import cc.iotkit.plugin.core.thing.actions.up.DeviceStateChange;
|
||||||
|
import cc.iotkit.plugin.core.thing.actions.up.PropertyReport;
|
||||||
|
import cc.iotkit.plugins.hydrovalve.analysis.ModBusConstants;
|
||||||
|
import cc.iotkit.plugins.hydrovalve.analysis.ModBusEntity;
|
||||||
|
import cc.iotkit.plugins.hydrovalve.analysis.ModBusRtuAnalysis;
|
||||||
|
import cc.iotkit.plugins.hydrovalve.conf.HydrovalveConfig;
|
||||||
|
import cc.iotkit.plugins.hydrovalve.utils.ByteUtils;
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import com.gitee.starblues.bootstrap.annotation.AutowiredType;
|
||||||
|
import com.gitee.starblues.core.PluginInfo;
|
||||||
|
import io.vertx.core.AbstractVerticle;
|
||||||
|
import io.vertx.core.buffer.Buffer;
|
||||||
|
import io.vertx.core.net.NetClient;
|
||||||
|
import io.vertx.core.net.NetClientOptions;
|
||||||
|
import io.vertx.core.net.NetSocket;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author:tfd
|
||||||
|
* @Date:2024/1/9 17:06
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class ModbusVerticle extends AbstractVerticle {
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private HydrovalveConfig modbusConfig;
|
||||||
|
|
||||||
|
private NetClient netClient;
|
||||||
|
|
||||||
|
private NetSocket socket;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@AutowiredType(AutowiredType.Type.MAIN_PLUGIN)
|
||||||
|
private IThingService thingService;
|
||||||
|
|
||||||
|
ModBusRtuAnalysis analysis=new ModBusRtuAnalysis();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PluginInfo pluginInfo;
|
||||||
|
|
||||||
|
private int connectState = 0;
|
||||||
|
|
||||||
|
private long timerID;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
log.info("init start");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Scheduled(initialDelay = 2, fixedRate = 5, timeUnit = TimeUnit.SECONDS)
|
||||||
|
public void initClient() {
|
||||||
|
if (connectState > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
connectState = 1;
|
||||||
|
NetClientOptions options = new NetClientOptions();
|
||||||
|
options.setReconnectAttempts(Integer.MAX_VALUE);
|
||||||
|
options.setReconnectInterval(20000L);
|
||||||
|
netClient = vertx.createNetClient(options);
|
||||||
|
netClient.connect(modbusConfig.getPort(), modbusConfig.getHost())
|
||||||
|
.onComplete(result -> {
|
||||||
|
if (result.succeeded()) {
|
||||||
|
connectState = 2;
|
||||||
|
log.info("connect modbus slave success");
|
||||||
|
socket = result.result();
|
||||||
|
thingService.post(pluginInfo.getPluginId(), DeviceRegister.builder()
|
||||||
|
.id(UUID.randomUUID().toString())
|
||||||
|
.productKey("PYWH4r8xBzsfn3XB")
|
||||||
|
.deviceName(String.format("modbus_%d", 1))
|
||||||
|
.build());
|
||||||
|
stateChange(DeviceState.ONLINE,String.format("modbus_%d", 1));
|
||||||
|
socket.handler(data -> {
|
||||||
|
String hexStr = ByteUtils.BinaryToHexString(data.getBytes(), false);
|
||||||
|
log.info("modbus received message:{}", hexStr);
|
||||||
|
//获取功能码
|
||||||
|
if(0x03==data.getBytes()[1]){
|
||||||
|
ModBusEntity ret = analysis.unPackCmd2Entity(data.getBytes());
|
||||||
|
Map<String, Object> params = new HashMap<>();
|
||||||
|
params.put("devSwith" , Integer.parseInt(ByteUtils.BinaryToHexString(getData(ret.getData()),false)));//数据标识
|
||||||
|
thingService.post(pluginInfo.getPluginId(),
|
||||||
|
PropertyReport.builder().deviceName(String.format("modbus_%d", ret.getDevAddr())).productKey("PwMfpXmp4ZWkGahn")
|
||||||
|
.params(params)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}).closeHandler(res -> {
|
||||||
|
connectState = 0;
|
||||||
|
vertx.cancelTimer(timerID);
|
||||||
|
log.info("modbus tcp connection closed!");
|
||||||
|
stateChange(DeviceState.OFFLINE,String.format("modbus_%d", 1));
|
||||||
|
}
|
||||||
|
).exceptionHandler(res -> {
|
||||||
|
connectState = 0;
|
||||||
|
vertx.cancelTimer(timerID);
|
||||||
|
log.info("modbus tcp connection exce!");
|
||||||
|
stateChange(DeviceState.OFFLINE,String.format("modbus_%d", 1));
|
||||||
|
});
|
||||||
|
timerID = vertx.setPeriodic(modbusConfig.getInterval(), t -> {
|
||||||
|
readDataTask();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
connectState = 0;
|
||||||
|
log.info("connect modbus tcp error", result.cause());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.onFailure(e -> {
|
||||||
|
log.error("modbus connect failed", e);
|
||||||
|
connectState = 0;
|
||||||
|
})
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readDataTask() {
|
||||||
|
log.info("readData:" + socket);
|
||||||
|
if (socket != null) {
|
||||||
|
ModBusEntity read=new ModBusEntity();
|
||||||
|
read.setFunc(ModBusConstants.FUN_CODE3);
|
||||||
|
read.setDevAddr((byte) 1);
|
||||||
|
Integer addr=1;
|
||||||
|
Integer length=1;
|
||||||
|
String a1= StringUtils.leftPad(addr.toHexString(addr),4,'0')+StringUtils.leftPad(addr.toHexString(length),4,'0');
|
||||||
|
read.setData(ByteUtils.hexStrToBinaryStr(a1));
|
||||||
|
byte[] msg = analysis.packCmd4Entity(read);
|
||||||
|
sendMsg(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() throws Exception {
|
||||||
|
if (netClient != null) {
|
||||||
|
netClient.close();
|
||||||
|
}
|
||||||
|
vertx.cancelTimer(timerID);
|
||||||
|
connectState = 0;
|
||||||
|
super.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] getData(byte[] data) {
|
||||||
|
int lenth=data[0];
|
||||||
|
byte[] val = new byte[lenth];
|
||||||
|
System.arraycopy(data, 1, val, 0, lenth);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stateChange(DeviceState state,String deviceName) {
|
||||||
|
thingService.post(pluginInfo.getPluginId(),
|
||||||
|
DeviceStateChange.builder()
|
||||||
|
.id(IdUtil.simpleUUID())
|
||||||
|
.state(state).productKey("PYWH4r8xBzsfn3XB").deviceName(deviceName)
|
||||||
|
.time(System.currentTimeMillis())
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendMsg(byte[] msg) {
|
||||||
|
log.info("modbus send msg data:{}", ByteUtils.BinaryToHexString(msg,false));
|
||||||
|
Buffer data = Buffer.buffer(msg);
|
||||||
|
socket.write(data, r -> {
|
||||||
|
if (r.succeeded()) {
|
||||||
|
log.info("modbus msg send success:{}", ByteUtils.BinaryToHexString(msg,false));
|
||||||
|
} else {
|
||||||
|
log.error("modbus msg send failed", r.cause());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package cc.iotkit.plugins.hydrovalve.utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author:tfd
|
||||||
|
* @Date:2024/1/8 15:15
|
||||||
|
*/
|
||||||
|
public class ByteUtils {
|
||||||
|
/**
|
||||||
|
* 将十六进制的字符串转换成字节数组
|
||||||
|
*
|
||||||
|
* @param hexString
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static byte[] hexStrToBinaryStr(String hexString) {
|
||||||
|
|
||||||
|
if (hexString==null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
hexString = hexString.replaceAll(" ", "");
|
||||||
|
int len = hexString.length();
|
||||||
|
int index = 0;
|
||||||
|
byte[] bytes = new byte[len / 2];
|
||||||
|
while (index < len) {
|
||||||
|
String sub = hexString.substring(index, index + 2);
|
||||||
|
bytes[index/2] = (byte)Integer.parseInt(sub,16);
|
||||||
|
index += 2;
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}catch (Exception e){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字节数组转换成十六进制的字符串
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static String BinaryToHexString(byte[] bytes,boolean isBalank) {
|
||||||
|
String hexStr = "0123456789ABCDEF";
|
||||||
|
String result = "";
|
||||||
|
String hex = "";
|
||||||
|
Boolean feStart=true;
|
||||||
|
for (byte b : bytes) {
|
||||||
|
hex = String.valueOf(hexStr.charAt((b & 0xF0) >> 4));
|
||||||
|
hex += String.valueOf(hexStr.charAt(b & 0x0F));
|
||||||
|
if("FE".equals(hex) && feStart){
|
||||||
|
continue;
|
||||||
|
}else {
|
||||||
|
feStart=false;
|
||||||
|
}
|
||||||
|
result += hex + (isBalank?" ":"");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
plugin:
|
||||||
|
runMode: prod
|
||||||
|
mainPackage: cc.iotkit.plugin
|
||||||
|
|
||||||
|
hydrovalve:
|
||||||
|
host: 25on621889.goho.co
|
||||||
|
port: 38807
|
||||||
|
interval: 20000
|
|
@ -0,0 +1,23 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "host",
|
||||||
|
"name": "服务端ip",
|
||||||
|
"type": "text",
|
||||||
|
"value": "25on621889.goho.co",
|
||||||
|
"desc": "服务端ip"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "port",
|
||||||
|
"name": "服务端端口",
|
||||||
|
"type": "number",
|
||||||
|
"value": 38807,
|
||||||
|
"desc": "服务端端口"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "interval",
|
||||||
|
"name": "采集频率",
|
||||||
|
"type": "number",
|
||||||
|
"value": 20000,
|
||||||
|
"desc": "采集频率"
|
||||||
|
}
|
||||||
|
]
|
Loading…
Reference in New Issue