|
@@ -0,0 +1,190 @@
|
|
|
+package com.jg.service.impl;
|
|
|
+
|
|
|
+import com.alibaba.fastjson2.JSON;
|
|
|
+import com.alibaba.fastjson2.JSONArray;
|
|
|
+import com.jg.common.ValueType;
|
|
|
+import com.jg.service.ModBusService;
|
|
|
+import com.jg.util.ModBusUtil;
|
|
|
+import com.jg.util.WebSocketServer;
|
|
|
+import com.jg.vo.ShowVo;
|
|
|
+import com.jg.vo.TagVo;
|
|
|
+import com.serotonin.modbus4j.BatchRead;
|
|
|
+import com.serotonin.modbus4j.BatchResults;
|
|
|
+import com.serotonin.modbus4j.ModbusMaster;
|
|
|
+import com.serotonin.modbus4j.code.DataType;
|
|
|
+import com.serotonin.modbus4j.locator.BaseLocator;
|
|
|
+import jdk.nashorn.internal.ir.annotations.Reference;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.boot.context.event.ApplicationReadyEvent;
|
|
|
+import org.springframework.context.event.EventListener;
|
|
|
+import org.springframework.scheduling.annotation.Scheduled;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.net.URISyntaxException;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.nio.file.Files;
|
|
|
+import java.nio.file.Paths;
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class ModBusServiceImpl implements ModBusService {
|
|
|
+
|
|
|
+ private static final Map<Long, ModbusMaster> MASTER_MAP = new HashMap<>(64);
|
|
|
+
|
|
|
+ @Value("${modbus.host}")
|
|
|
+ private String host;
|
|
|
+
|
|
|
+ @Value("${modbus.port}")
|
|
|
+ private Integer port;
|
|
|
+
|
|
|
+ @Reference
|
|
|
+ private WebSocketServer webSocketServer;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建ModBusTCP连接
|
|
|
+ */
|
|
|
+ @EventListener(ApplicationReadyEvent.class)
|
|
|
+ private void createConn() {
|
|
|
+ // 创建ModBus连接, 存入MASTER_MAP
|
|
|
+// List<CollectModuleInfo> collectModuleInfoList = collectModuleInfoService.findCurrent();
|
|
|
+// log.info("[查询采集模块列表]: {}", collectModuleInfoList);
|
|
|
+// if (!CollectionUtils.isEmpty(collectModuleInfoList)) {
|
|
|
+// for (CollectModuleInfo collectModuleInfo : collectModuleInfoList) {
|
|
|
+// Long collectModuleInfoId = collectModuleInfo.getId();
|
|
|
+// MODULE_INFO_MAP.put(collectModuleInfoId, collectModuleInfo);
|
|
|
+// // 循环创建ModBus连接
|
|
|
+// ModbusMaster modbusMaster = MASTER_MAP.get(collectModuleInfoId);
|
|
|
+// if (null == modbusMaster) {
|
|
|
+// // 创建ModBus连接, 存入Map, key: 采集模块id, value: ModBus连接
|
|
|
+// modbusMaster = ModBusUtil.createMaster(collectModuleInfo);
|
|
|
+// MASTER_MAP.put(collectModuleInfoId, modbusMaster);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// } else {
|
|
|
+//// throw new BizException("连接失败! 没有查询到ModBus模块信息!");
|
|
|
+// }
|
|
|
+// log.warn("[开始连接采集模块]: {}", JSON.toJSONString(collectModuleInfoList));
|
|
|
+ ModbusMaster master = ModBusUtil.createMaster(host, port);
|
|
|
+ MASTER_MAP.put(1l, master);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Scheduled(fixedRate = 1000)
|
|
|
+ private void readTagsValue(){
|
|
|
+// ArrayList<ShowVo> showVos = new ArrayList<>();
|
|
|
+ JSONArray array = new JSONArray();
|
|
|
+ String s = "";
|
|
|
+ try {
|
|
|
+ s = new String(Files.readAllBytes(Paths.get(ClassLoader.getSystemResource("tag.json").toURI())), StandardCharsets.UTF_8);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ List<TagVo> tagVos = JSON.parseArray(s, TagVo.class);
|
|
|
+ BatchRead<String> batch = new BatchRead<>();
|
|
|
+ for (TagVo tagVo: tagVos){
|
|
|
+ Integer slaveId = tagVo.getSlaveId();
|
|
|
+ Integer functionCode = tagVo.getFunctionCode();
|
|
|
+ int offset = tagVo.getOffset();
|
|
|
+ String tag = tagVo.getTag();
|
|
|
+ String dataType = tagVo.getDataType();
|
|
|
+ switch (functionCode) {
|
|
|
+ case 1:
|
|
|
+ batch.addLocator(tag, BaseLocator.coilStatus(slaveId, offset));
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ batch.addLocator(tag, BaseLocator.inputStatus(slaveId, offset));
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ batch.addLocator(tag, BaseLocator.holdingRegister(slaveId, offset, getValueType(dataType)));
|
|
|
+ break;
|
|
|
+ case 4:
|
|
|
+ batch.addLocator(tag, BaseLocator.inputRegister(slaveId, offset, getValueType(dataType)));
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ batch.setContiguousRequests(false);
|
|
|
+ ModbusMaster modbusMaster = MASTER_MAP.get(1l);
|
|
|
+ try {
|
|
|
+ if (!modbusMaster.isInitialized()) {
|
|
|
+ modbusMaster.init();
|
|
|
+ }
|
|
|
+ modbusMaster.setTimeout(500);
|
|
|
+ BatchResults<String> results = modbusMaster.send(batch);
|
|
|
+ for (TagVo tagVo: tagVos){
|
|
|
+// log.info("采集中文: {}, 值: {}", tagVo.getDesc(), results.getValue(tagVo.getTag()));
|
|
|
+ Object value = results.getValue(tagVo.getTag());
|
|
|
+ BigDecimal bigDecimalValue = convertToBigDecimal(value);
|
|
|
+ ShowVo showVo = new ShowVo();
|
|
|
+ showVo.setName(tagVo.getDesc());
|
|
|
+ showVo.setValue(bigDecimalValue);
|
|
|
+ showVo.setUnit(tagVo.getUnit());
|
|
|
+// showVos.add(showVo);
|
|
|
+ array.add(showVo);
|
|
|
+ }
|
|
|
+ webSocketServer.sendInfo(array.toString(), "push");
|
|
|
+ modbusMaster.destroy();
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("采集模块Id: {}, 读取失败: {}", 1l, e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取数据类型
|
|
|
+ * 说明:此处可根据实际项目情况进行拓展
|
|
|
+ * 1.swap 交换
|
|
|
+ * 2.大端/小端,默认是大端
|
|
|
+ * 3.拓展其他数据类型
|
|
|
+ *
|
|
|
+ * @param type Value Type
|
|
|
+ * @return Modbus Data Type
|
|
|
+ */
|
|
|
+ public static int getValueType(String type) {
|
|
|
+ switch (type.toLowerCase()) {
|
|
|
+ case ValueType.LONG:
|
|
|
+ return DataType.FOUR_BYTE_INT_SIGNED;
|
|
|
+ case ValueType.FLOAT:
|
|
|
+ return DataType.FOUR_BYTE_FLOAT;
|
|
|
+ case ValueType.DOUBLE:
|
|
|
+ return DataType.EIGHT_BYTE_FLOAT;
|
|
|
+ default:
|
|
|
+ return DataType.TWO_BYTE_INT_UNSIGNED;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将 Object 转换为 BigDecimal
|
|
|
+ **/
|
|
|
+ private static BigDecimal convertToBigDecimal(Object obj) {
|
|
|
+ // 处理 obj 为 null 的情况,返回 -1
|
|
|
+ if (obj == null) {
|
|
|
+ return BigDecimal.valueOf(-1);
|
|
|
+ }
|
|
|
+ if (obj instanceof BigDecimal) {
|
|
|
+ return (BigDecimal) obj;
|
|
|
+ } else if (obj instanceof Integer) {
|
|
|
+ return BigDecimal.valueOf((Integer) obj);
|
|
|
+ } else if (obj instanceof Double) {
|
|
|
+ return BigDecimal.valueOf((Double) obj);
|
|
|
+ } else if (obj instanceof String) {
|
|
|
+ return new BigDecimal((String) obj);
|
|
|
+ } else if (obj instanceof Float){
|
|
|
+ return BigDecimal.valueOf(((Float) obj).doubleValue());
|
|
|
+ } else if (obj instanceof Boolean) {
|
|
|
+ return BigDecimal.valueOf((Boolean) obj ? 1 : 0);
|
|
|
+ } else {
|
|
|
+ throw new IllegalArgumentException("Unsupported object type: " + obj.getClass());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void startCollect() {
|
|
|
+ createConn();
|
|
|
+ readTagsValue();
|
|
|
+ }
|
|
|
+
|
|
|
+}
|