diff --git a/db/upgrade1128.sql b/db/upgrade1128.sql index 07180b1..e6b05b3 100644 --- a/db/upgrade1128.sql +++ b/db/upgrade1128.sql @@ -34,4 +34,6 @@ CREATE TABLE `ied_dl_config` ( `todel` int(11) DEFAULT NULL COMMENT '下载后删除', `active` int(11) DEFAULT NULL COMMENT '0:停用; 1:启用;', PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; \ No newline at end of file +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +ALTER TABLE `i2sync_field` ADD COLUMN `attach` VARCHAR(45) NULL COMMENT 'sensorid尾部附加' AFTER `dest_field_name`; \ No newline at end of file diff --git a/db/upgrade1210.sql b/db/upgrade1210.sql new file mode 100644 index 0000000..9c613ee --- /dev/null +++ b/db/upgrade1210.sql @@ -0,0 +1 @@ +ALTER TABLE `warn_rule` ADD COLUMN `notify_com` INT(11) NULL DEFAULT NULL COMMENT '0:不通知; 1:通知' AFTER `active`; diff --git a/pom.xml b/pom.xml index ba251d8..f9a3249 100644 --- a/pom.xml +++ b/pom.xml @@ -193,11 +193,19 @@ asn1bean 1.14.0 + org.openmuc j60870 1.7.2 + + + + com.fazecast + jSerialComm + 2.11.0 + diff --git a/src/main/java/com/xydl/cac/controller/I2syncController.java b/src/main/java/com/xydl/cac/controller/I2syncController.java index 3542d3d..84f4fcf 100644 --- a/src/main/java/com/xydl/cac/controller/I2syncController.java +++ b/src/main/java/com/xydl/cac/controller/I2syncController.java @@ -2,10 +2,7 @@ package com.xydl.cac.controller; import com.alibaba.excel.util.StringUtils; import com.xydl.cac.adapter.BusiAdapter; -import com.xydl.cac.entity.I2syncConfig; -import com.xydl.cac.entity.I2syncField; -import com.xydl.cac.entity.I2syncRecord; -import com.xydl.cac.entity.ModevType; +import com.xydl.cac.entity.*; import com.xydl.cac.exception.BusinessException; import com.xydl.cac.model.Response; import com.xydl.cac.model.i2sync.Attr; @@ -13,7 +10,9 @@ import com.xydl.cac.model.i2sync.Datanode; import com.xydl.cac.model.i2sync.Monitordata; import com.xydl.cac.model.i2sync.Request; import com.xydl.cac.service.I2syncService; +import com.xydl.cac.service.ModevTypePointService; import com.xydl.cac.service.ModevTypeService; +import com.xydl.cac.transform.I2DataTransformer; import com.xydl.cac.util.DateUtil; import com.xydl.cac.util.JSONUtil; import io.swagger.annotations.Api; @@ -37,7 +36,11 @@ public class I2syncController extends BasicController { @Resource ModevTypeService modevTypeService; @Resource + ModevTypePointService modevTypePointService; + @Resource BusiAdapter busiAdapter; + @Resource + I2DataTransformer dataTransformer; @GetMapping("status") @ApiOperation("查询状态") @@ -107,37 +110,33 @@ public class I2syncController extends BasicController { @ApiOperation("预览xml结构") public Response prewXml(Integer modevtypeId) throws Exception { ModevType modevType = modevTypeService.detail(modevtypeId); + List points = modevTypePointService.listAll(modevtypeId); List fieldList = service.listFieldConfig(modevType.getTablename()); - List attrs = new ArrayList<>(); - Attr attr = new Attr(); - attr.setName("Phase"); - attr.setValue("A相"); - attr.setAlarm("FALSE"); - attrs.add(attr); - for (I2syncField field : fieldList) { - attr = new Attr(); - attr.setName(field.getDestFieldName()); - attr.setValue("100.0"); - attr.setAlarm("FALSE"); - attrs.add(attr); + NSensor sensor = NSensor.builder() + .id(12) + .typeId(modevtypeId) + .sensorCode("HNHFT001Q1W000104") + .equipmentId("HNHFT001Q1W000104") + .phase("ABC相") + .build(); + I2syncRecord record = I2syncRecord.builder() + .build(); + I2syncConfig config = I2syncConfig.builder() + .typeCode(modevType.getTypeCode()) + .build(); + List> dataList = new ArrayList<>(); + Map map = new HashMap<>(); + map.put("acquisitionTime", DateUtil.format(new Date())); + for (ModevTypePoint point : points) { + map.put(point.getField(), 1.25); } - Datanode node = new Datanode(); - node.setSensorid("HNHFT001Q1W000104"); - node.setType(modevType.getTypeCode()); - node.setEquipmentid("HNHFT001Q1W000104"); - node.setTimestamp(DateUtil.format(new Date())); - node.setAttr(attrs); - List nodeList = new ArrayList<>(); - nodeList.add(node); - Monitordata monitordata = new Monitordata(); - monitordata.setCacid("HNHFT001Q1W000104"); - monitordata.setDatanodenum(1); - monitordata.setDatanode(nodeList); - Request request = new Request(); - request.setMonitordata(monitordata); + dataList.add(map); + + Request request = dataTransformer.transform(sensor, record, config, fieldList, dataList); + String xml = JSONUtil.object2Xml(request); Response resp = Response.success(xml); - if (StringUtils.isBlank(node.getType())) { + if (StringUtils.isBlank(modevType.getTypeCode())) { resp.setWarnMsg("该类型还未配置对应的类型编码将导致type为空"); } return resp; diff --git a/src/main/java/com/xydl/cac/controller/IcdConfigController.java b/src/main/java/com/xydl/cac/controller/IcdConfigController.java index 5946c4b..9714c6f 100644 --- a/src/main/java/com/xydl/cac/controller/IcdConfigController.java +++ b/src/main/java/com/xydl/cac/controller/IcdConfigController.java @@ -10,6 +10,7 @@ import com.xydl.cac.iec.RealTimeDataService; import com.xydl.cac.model.ColumnModel; import com.xydl.cac.model.IcdAttUpdateModel; import com.xydl.cac.model.Response; +import com.xydl.cac.repository.IcdIedRepository; import com.xydl.cac.service.DataService; import com.xydl.cac.service.IcdFileConfigService; import io.swagger.annotations.Api; @@ -25,6 +26,7 @@ import javax.annotation.Resource; import javax.validation.constraints.NotNull; import java.nio.charset.Charset; import java.util.List; +import java.util.Optional; @RestController @Api(tags = {"IcdConfig相关接口"}) @@ -38,6 +40,8 @@ public class IcdConfigController extends BasicController { DataService dataService; @Resource RealTimeDataService realTimeDataService; + @Resource + IcdIedRepository iedRepository; @PostMapping("upload") @ApiOperation("上传客户端icd文件") @@ -161,8 +165,22 @@ public class IcdConfigController extends BasicController { if (RealTimeDataService.inDoing) { throw new BusinessException("请稍后再操作"); } - realTimeDataService.startCollect(iedId); - return Response.success("OK"); + Optional optional = iedRepository.findById(iedId); + if (!optional.isPresent()) { + throw new BusinessException("未找到该IED"); + } + IcdIed ied = optional.get(); + try { + realTimeDataService.startCollect(ied); + ied.setStart(Constants.TRUE); + iedRepository.save(ied); + return Response.success("OK"); + } catch (Exception ex) { + realTimeDataService.stopCollect(ied.getId()); + ied.setStart(Constants.FALSE); + iedRepository.save(ied); + return Response.fail(ex.getMessage()); + } } @PostMapping("stopCollect") @@ -174,7 +192,14 @@ public class IcdConfigController extends BasicController { if (RealTimeDataService.inDoing) { throw new BusinessException("请稍后再操作"); } - realTimeDataService.stopCollect(iedId); + Optional optional = iedRepository.findById(iedId); + if (!optional.isPresent()) { + throw new BusinessException("未找到该IED"); + } + IcdIed ied = optional.get(); + ied.setStart(Constants.FALSE); + iedRepository.save(ied); + realTimeDataService.stopCollect(ied.getId()); return Response.success("OK"); } diff --git a/src/main/java/com/xydl/cac/controller/IecServerController.java b/src/main/java/com/xydl/cac/controller/IecServerController.java index 7997a2a..23fc49b 100644 --- a/src/main/java/com/xydl/cac/controller/IecServerController.java +++ b/src/main/java/com/xydl/cac/controller/IecServerController.java @@ -7,9 +7,9 @@ import com.xydl.cac.entity.constants.Constants; import com.xydl.cac.exception.BusinessException; import com.xydl.cac.iec.IecServerService; import com.xydl.cac.model.Response; +import com.xydl.cac.model.StaticVariable; import com.xydl.cac.service.IcdFileConfigService; import com.xydl.cac.service.IcdTransformService; -import com.xydl.cac.service.impl.IcdTransformServiceImpl; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; @@ -128,11 +128,15 @@ public class IecServerController extends BasicController { public Response> listTransform() throws Exception { List result = transformService.listTransform(); for (IcdTransform item : result) { - if (IcdTransformServiceImpl.rptFromActiveMap.containsKey(item.getRptFrom())) { + if (StaticVariable.rptFromActiveMap.containsKey(item.getRptFrom())) { item.setFromActive(true); + } else { + item.setFromActive(false); } - if (IcdTransformServiceImpl.rptToActiveMap.containsKey(item.getRptTo())) { + if (StaticVariable.rptToActiveMap.containsKey(item.getRptTo())) { item.setToActive(true); + } else { + item.setToActive(false); } } return Response.success(result); diff --git a/src/main/java/com/xydl/cac/controller/TestController.java b/src/main/java/com/xydl/cac/controller/TestController.java index d0c881d..78c8927 100644 --- a/src/main/java/com/xydl/cac/controller/TestController.java +++ b/src/main/java/com/xydl/cac/controller/TestController.java @@ -2,6 +2,7 @@ package com.xydl.cac.controller; import com.xydl.cac.model.Response; import com.xydl.cac.model.StaticVariable; +import com.xydl.cac.serialport.SerialPortServer; import com.xydl.cac.service.IcdFileConfigService; import com.xydl.cac.socket.WebSocketServer; import io.swagger.annotations.Api; @@ -12,11 +13,12 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; +import java.io.IOException; import java.util.HashMap; import java.util.List; @RestController -@Api(tags = {"测试接口"}) +@Api(tags = {"测试接口文档"}) @RequestMapping("test") @Slf4j public class TestController extends BasicController { @@ -26,6 +28,9 @@ public class TestController extends BasicController { @Resource WebSocketServer webSocketServer; + @Resource + SerialPortServer serialPortService; + @GetMapping("compare61850") @ApiOperation("比对61850的不同点") public Response> compare61850() throws Exception { @@ -57,10 +62,52 @@ public class TestController extends BasicController { return Response.success(StaticVariable.sensorLastDataMap); } + @GetMapping("iecServerMap") + @ApiOperation("iecServerMap") + public Response iecServerMap() { + return Response.success(StaticVariable.iecServerMap); + } + + @GetMapping("rptFromActiveMap") + @ApiOperation("rptFromActiveMap") + public Response rptFromActiveMap() { + return Response.success(StaticVariable.rptFromActiveMap); + } + + @GetMapping("rptToActiveMap") + @ApiOperation("rptToActiveMap") + public Response rptToActiveMap() { + return Response.success(StaticVariable.rptToActiveMap); + } + @GetMapping("clearMap") @ApiOperation("clearMap") public void clearMap() { StaticVariable.sensorLastDataMap.clear(); StaticVariable.paramRelationMap.clear(); } + + @GetMapping("/discover") + public Response discoverSerialPort() { + serialPortService.discoverSerialPort(); + return Response.fail("未找到"); + } + + @GetMapping("/open") + public Response openSerialPort() { + return Response.success(serialPortService.openSerialPort()); + } + + @GetMapping("/send") + public String sendData() throws IOException { + //发送数据注意,提前与接收设备沟通好协议,发送什么样类型的数据设备才可以进行响应,否则设备无响应 + serialPortService.sendData(); + return "Data sent>>>"; + } + + @GetMapping("/close") + public String closeSerialPort() { + serialPortService.closeSerialPort(); + return "Serial port closed"; + } } diff --git a/src/main/java/com/xydl/cac/entity/I2syncField.java b/src/main/java/com/xydl/cac/entity/I2syncField.java index 76bb7be..98d1a05 100644 --- a/src/main/java/com/xydl/cac/entity/I2syncField.java +++ b/src/main/java/com/xydl/cac/entity/I2syncField.java @@ -33,4 +33,7 @@ public class I2syncField { @Column(name = "dest_field_name") private String destFieldName; + @Column(name = "attach") + private String attach; + } \ No newline at end of file diff --git a/src/main/java/com/xydl/cac/entity/IcdIed.java b/src/main/java/com/xydl/cac/entity/IcdIed.java index 818be12..405896e 100644 --- a/src/main/java/com/xydl/cac/entity/IcdIed.java +++ b/src/main/java/com/xydl/cac/entity/IcdIed.java @@ -46,4 +46,11 @@ public class IcdIed { @ApiModelProperty(name = "端口") @Column(name = "port") private Integer port; + + @Transient + private boolean connected; + @Transient + private int retry; + @Transient + private int seconds; } \ No newline at end of file diff --git a/src/main/java/com/xydl/cac/entity/WarnRule.java b/src/main/java/com/xydl/cac/entity/WarnRule.java index 9464296..9bfac57 100644 --- a/src/main/java/com/xydl/cac/entity/WarnRule.java +++ b/src/main/java/com/xydl/cac/entity/WarnRule.java @@ -77,6 +77,10 @@ public class WarnRule { @Column(name = "active") private Integer active; + @ApiModelProperty("状态 0:不通知 1:通知") + @Column(name = "notify_com") + private Integer notifyCom; + @ApiModelProperty("最后数据采集时间") @Column(name = "last_d_time") private Date lastDTime; diff --git a/src/main/java/com/xydl/cac/iec/IEDCollectService.java b/src/main/java/com/xydl/cac/iec/IEDCollectService.java index 5d81d77..5543849 100644 --- a/src/main/java/com/xydl/cac/iec/IEDCollectService.java +++ b/src/main/java/com/xydl/cac/iec/IEDCollectService.java @@ -15,6 +15,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.util.CollectionUtils; +import java.net.SocketException; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -55,7 +56,8 @@ public class IEDCollectService { } public void connect() throws Exception { - iecClient.connect(ied, xml); + iecClient.init(ied, xml); + iecClient.connect(); } public void disconnect() { @@ -87,7 +89,10 @@ public class IEDCollectService { StaticVariable.doneWarnMap.put(key, "1"); _webSocketServer.sendMessage(err, null); } - RealTimeDataService.onErrorCheck(ied.getId()); + if (ex instanceof SocketException) { + NetErrorThread thread = new NetErrorThread(ied.getId()); + thread.start(); + } } finally { iecClient.disconnect(); } @@ -116,23 +121,36 @@ public class IEDCollectService { } private void collectAndSaveValue(String paramindexNew, String paramindexT, String fc, Rptparamindex rpt) throws Exception { - String value = iecClient.getValue(paramindexNew, fc); - String time = iecClient.getValue(paramindexT, fc); + // 更新关联关系缓存 + String key = paramindexNew + "_" + fc; + String value = rpt.getEqmid() + "," + rpt.getColname(); + StaticVariable.paramRelationMap.put(key, value); + key = paramindexT + "_" + fc; + value = rpt.getEqmid() + ",acquisitionTime"; + StaticVariable.paramRelationMap.put(key, value); + + // 采集数据 + BasicDataAttribute valueNode = iecClient.getNode(paramindexNew, fc); + BasicDataAttribute timeNode = iecClient.getNode(paramindexT, fc); + value = valueNode.getValueString(); + String time = timeNode.getValueString(); log.info("采集到" + fc + " " + paramindexNew + "=" + value + ", t=" + time); + if ("NaN".equalsIgnoreCase(value)) { + return; + } time = DateUtil.fromZoneUTCToLocal(time); + if (time == null) { + return; + } time = this.makeSameTime(rpt.getEqmid(), time); _dataService.insertData(rpt.getTablename(), rpt.getEqmid(), time, rpt.getColname(), value); // 更新最新数据缓存 - updateLastData(rpt.getEqmid(), rpt.getColname(), value, time); + StaticVariable.updateLastData(rpt.getEqmid(), rpt.getColname(), value, time); - // 更新关联关系缓存 - String key = paramindexNew + "_" + fc; - value = rpt.getEqmid() + "," + rpt.getColname(); - StaticVariable.paramRelationMap.put(key, value); - key = paramindexT + "_" + fc; - value = rpt.getEqmid() + ",acquisitionTime"; - StaticVariable.paramRelationMap.put(key, value); + // 更新服务端 + StaticVariable.updateServerNodeValue(valueNode); + StaticVariable.updateServerNodeValue(timeNode); } private String makeSameTime(Integer eqmid, String time) { @@ -229,34 +247,4 @@ public class IEDCollectService { } } - public static void updateLastData(Integer eqmid, String colname, String value, String time) { - HashMap map = StaticVariable.sensorLastDataMap.get(eqmid); - if (map == null) { - map = new HashMap<>(); - StaticVariable.sensorLastDataMap.put(eqmid, map); - } - map.put(colname, value); - if (time != null) { - map.put("acquisitionTime", time); - } - } - - public static void updateLastData(BasicDataAttribute bda) { - try { - String ref = bda.getReference().toString(); - String key = ref + "_" + bda.getFc().toString(); - if (StaticVariable.paramRelationMap.containsKey(key)) { - String value = StaticVariable.paramRelationMap.get(key); - String[] str = value.split(","); - Integer eqmid = Integer.parseInt(str[0]); - String colname = str[1]; - value = bda.getValueString(); - if ("acquisitionTime".equals(colname)) { - value = DateUtil.fromZoneUTCToLocal(value); - } - updateLastData(eqmid, colname, value, null); - } - } catch (Exception ignore) { - } - } } diff --git a/src/main/java/com/xydl/cac/iec/IecClient.java b/src/main/java/com/xydl/cac/iec/IecClient.java index 025aeca..d87fbb0 100644 --- a/src/main/java/com/xydl/cac/iec/IecClient.java +++ b/src/main/java/com/xydl/cac/iec/IecClient.java @@ -29,9 +29,12 @@ public class IecClient implements ClientEventListener { ServerModel serverModel; public boolean keep = false; + public boolean connected = false; private RealTimeDataService realTimeDataService; private WebSocketServer webSocketServer; - public int retry = 10; + public int retry = 0; + public int seconds = 0; + private boolean inRetry = false; public Date lastReportTime; public IecClient() { @@ -42,16 +45,20 @@ public class IecClient implements ClientEventListener { webSocketServer = _webSocketServer; } - public void connect(IcdIed _ied, String xml) throws Exception { + public void init(IcdIed _ied, String xml) throws Exception { InputStream in = IOUtils.toInputStream(xml, StandardCharsets.UTF_8); - this.connect(_ied, in); + this.init(_ied, in); } - public void connect(IcdIed _ied, InputStream in) throws Exception { + public void init(IcdIed _ied, InputStream in) throws Exception { ied = _ied; + serverModel = SclParser.parse(in).get(0); + } + + public void connect() throws Exception { title = new int[]{1, 3, 9999, 33}; - if (StringUtils.isNotBlank(_ied.getApTitle())) { - String[] strs = _ied.getApTitle().replaceAll(" ", ",").split(","); + if (StringUtils.isNotBlank(ied.getApTitle())) { + String[] strs = ied.getApTitle().replaceAll(" ", ",").split(","); if (strs.length == 4) { title[0] = Integer.parseInt(strs[0]); title[1] = Integer.parseInt(strs[1]); @@ -69,14 +76,15 @@ public class IecClient implements ClientEventListener { clientSap.setTSelRemote(new byte[]{0, 1}); clientSap.setTSelLocal(new byte[]{0, 0}); clientSap.setApTitleCalled(title); - serverModel = SclParser.parse(in).get(0); clientAssociation = clientSap.associate(InetAddress.getByName(ied.getIp()), ied.getPort(), null, this); clientAssociation.setServerModel(serverModel); + connected = true; } public void disconnect() { try { + connected = false; clientAssociation.disconnect(); clientAssociation = null; } catch (Exception ignore) { @@ -87,22 +95,31 @@ public class IecClient implements ClientEventListener { if (StaticVariable.shutdown == 1) { return; } + retry++; + seconds = 0; clientAssociation = clientSap.associate(InetAddress.getByName(ied.getIp()), ied.getPort(), null, this); clientAssociation.setServerModel(serverModel); log.info("61850订阅断线重连成功, ied=" + ied.getName() + ", ip=" + ied.getIp() + ", port=" + ied.getPort()); - retry = 10; - keep = true; + connected = true; + retry = 0; } public String getValue(String paramindex, String fc) throws Exception { + BasicDataAttribute node = this.getNode(paramindex, fc); + if (node != null) { + return node.getValueString(); + } + return null; + } + + public BasicDataAttribute getNode(String paramindex, String fc) throws Exception { FcModelNode node = (FcModelNode) serverModel.findModelNode(paramindex, Fc.valueOf(fc)); if (node == null) { throw new BusinessException("icd文件里未找到该节点, " + fc + " " + paramindex); } clientAssociation.getDataValues(node); if (node instanceof BasicDataAttribute) { - String value = ((BasicDataAttribute) node).getValueString(); - return value; + return (BasicDataAttribute) node; } return null; } @@ -119,7 +136,6 @@ public class IecClient implements ClientEventListener { } } log.info("61850订阅成功, ied=" + ied.getName() + ", ip=" + ied.getIp() + ", port=" + ied.getPort()); - keep = true; } public void disableReporting() { @@ -144,7 +160,6 @@ public class IecClient implements ClientEventListener { } else { log.info("61850停止订阅, ied=" + ied.getName() + ", ip=" + ied.getIp() + ", port=" + ied.getPort()); } - keep = false; } public List listFile(String path) throws Exception { @@ -170,36 +185,31 @@ public class IecClient implements ClientEventListener { @Override public void associationClosed(IOException e) { - if (keep) { + if (keep && !inRetry) { + inRetry = true; + retry = 0; + seconds = 0; this.disableReporting(); this.disconnect(); - while (retry > 0 && StaticVariable.shutdown == 0) { - retry--; + while (!connected && StaticVariable.shutdown == 0) { try { - if (retry >= 5) { - StaticVariable.wait(10); + Thread.sleep(1000); + seconds++; + if (retry < 10 && seconds > 60) { this.reconnect(); - } else if (retry == 4) { - log.warn("61850订阅断线重连已失败5次, ied=" + ied.getName() + ", ip=" + ied.getIp() + ", port=" + ied.getPort()); - StaticVariable.wait(60); + } else if (seconds > 60 * 60) { this.reconnect(); - } else if (retry >= 1) { - StaticVariable.wait(60); - this.reconnect(); - } else { - String err = "61850订阅断线重连已失败多次不再重连. ied=" + ied.getName() + ", ip=" + ied.getIp() + ", port=" + ied.getPort(); - log.warn(err); - if (realTimeDataService != null && ied != null) { - realTimeDataService.stopCollect(ied.getId()); - } - if (webSocketServer != null) { - webSocketServer.sendMessage(err, null); - } } - break; } catch (Exception ignore) { + String err = "61850订阅断线重连失败" + retry + "次, ied=" + + ied.getName() + ", ip=" + ied.getIp() + ", port=" + ied.getPort(); + log.warn(err); + if (webSocketServer != null && retry >= 10) { + webSocketServer.sendMessage(err, null); + } } } + inRetry = false; } } @@ -211,7 +221,8 @@ public class IecClient implements ClientEventListener { .port(102) .apTitle("1 3 9999 33") .build(); - iecClient.connect(ied, new FileInputStream("C:/资料/om.SCD")); + iecClient.init(ied, new FileInputStream("C:/资料/om.SCD")); + iecClient.connect(); String str = iecClient.getValue("OMDLMONT/SPDC1.MaxDsch.mag.f", "MX"); System.out.println(str); str = iecClient.getValue("OMDLMONT/SPDC1.MaxDsch.t", "MX"); diff --git a/src/main/java/com/xydl/cac/iec/IecServer.java b/src/main/java/com/xydl/cac/iec/IecServer.java index 86a8e4f..59fd140 100644 --- a/src/main/java/com/xydl/cac/iec/IecServer.java +++ b/src/main/java/com/xydl/cac/iec/IecServer.java @@ -2,6 +2,7 @@ package com.xydl.cac.iec; import com.beanit.iec61850bean.*; import com.xydl.cac.entity.IcdTransform; +import com.xydl.cac.model.StaticVariable; import com.xydl.cac.service.IcdTransformService; import com.xydl.cac.service.impl.IcdTransformServiceImpl; import lombok.extern.slf4j.Slf4j; @@ -57,7 +58,7 @@ public class IecServer implements ServerEventListener { if (ref.startsWith(item.getRptFrom())) { ref = ref.replace(item.getRptFrom(), item.getRptTo()); rptTo = item.getRptTo(); - IcdTransformServiceImpl.rptFromActiveMap.put(item.getRptFrom(), "1"); + StaticVariable.rptFromActiveMap.put(item.getRptFrom(), "1"); break; } } @@ -67,8 +68,10 @@ public class IecServer implements ServerEventListener { node.setValueFrom(bda); List bdas = new ArrayList<>(); bdas.add(node); - IcdTransformServiceImpl.rptToActiveMap.put(rptTo, "1"); + StaticVariable.rptToActiveMap.put(rptTo, "1"); serverSap.setValues(bdas); + } else { + StaticVariable.rptToActiveMap.remove(rptTo); } } diff --git a/src/main/java/com/xydl/cac/iec/IecServerService.java b/src/main/java/com/xydl/cac/iec/IecServerService.java index 9a38960..38cc22b 100644 --- a/src/main/java/com/xydl/cac/iec/IecServerService.java +++ b/src/main/java/com/xydl/cac/iec/IecServerService.java @@ -83,6 +83,7 @@ public class IecServerService { @PreDestroy private void stop() { + StaticVariable.shutdown = 1; Iterator it = StaticVariable.iecServerMap.keySet().iterator(); while (it.hasNext()) { Integer key = it.next(); diff --git a/src/main/java/com/xydl/cac/iec/NetErrorThread.java b/src/main/java/com/xydl/cac/iec/NetErrorThread.java new file mode 100644 index 0000000..accfbdf --- /dev/null +++ b/src/main/java/com/xydl/cac/iec/NetErrorThread.java @@ -0,0 +1,19 @@ +package com.xydl.cac.iec; + +import com.xydl.cac.model.StaticVariable; + +public class NetErrorThread extends Thread { + public int iedId; + + public NetErrorThread(Integer iedid) { + iedId = iedid; + } + + @Override + public void run() { + IecClient iecClient = StaticVariable.realTimeClientMap.get(iedId); + if (iecClient != null) { + iecClient.associationClosed(null); + } + } +} diff --git a/src/main/java/com/xydl/cac/iec/RealTimeDataService.java b/src/main/java/com/xydl/cac/iec/RealTimeDataService.java index 65d5378..b34eb52 100644 --- a/src/main/java/com/xydl/cac/iec/RealTimeDataService.java +++ b/src/main/java/com/xydl/cac/iec/RealTimeDataService.java @@ -36,36 +36,32 @@ public class RealTimeDataService { if (!CollectionUtils.isEmpty(list)) { for (IcdIed ied : list) { try { - this.startCollect(ied.getId()); + this.startCollect(ied); } catch (Exception ignore) { + NetErrorThread thread = new NetErrorThread(ied.getId()); + thread.start(); } } } } - public void startCollect(Integer iedId) throws BusinessException { - Optional optional = iedRepository.findById(iedId); - if (!optional.isPresent()) { - throw new BusinessException("未找到该IED"); - } - IcdIed ied = optional.get(); + public void startCollect(IcdIed ied) throws BusinessException { Optional optionalFile = fileRepository.findById(ied.getIcdFileId()); if (!optionalFile.isPresent()) { throw new BusinessException("未找到该icd文件"); } inDoing = true; IcdFile icdFile = optionalFile.get(); + IecClient iecClient = new IecClient(this, webSocketServer); try { - IecClient iecClient = new IecClient(this, webSocketServer); - iecClient.connect(ied, icdFile.getXml()); - iecClient.enableReporting(); - ied.setStart(Constants.TRUE); - iedRepository.save(ied); + iecClient.init(ied, icdFile.getXml()); + iecClient.keep = true; StaticVariable.realTimeClientMap.put(ied.getId(), iecClient); + iecClient.connect(); + iecClient.enableReporting(); } catch (Exception ex) { String err = "61850订阅异常, ied=" + ied.getName() + ", ip=" + ied.getIp() + ", port=" + ied.getPort(); log.error(err, ex); - this.stopCollect(iedId); throw new BusinessException(err); } finally { inDoing = false; @@ -73,29 +69,12 @@ public class RealTimeDataService { } public void stopCollect(Integer iedId) { - this.onlyStop(iedId); - Optional optional = iedRepository.findById(iedId); - if (optional.isPresent()) { - IcdIed ied = optional.get(); - ied.setStart(Constants.FALSE); - iedRepository.save(ied); - } - } - - public static void onErrorCheck(Integer iedId) { - IecClient iecClient = StaticVariable.realTimeClientMap.get(iedId); - if (iecClient != null) { - iecClient.associationClosed(null); - } - } - - private void onlyStop(Integer iedId) { IecClient iecClient = StaticVariable.realTimeClientMap.get(iedId); if (iecClient != null) { + StaticVariable.realTimeClientMap.remove(iedId); iecClient.keep = false; iecClient.disableReporting(); iecClient.disconnect(); - StaticVariable.realTimeClientMap.remove(iedId); } } @@ -109,7 +88,7 @@ public class RealTimeDataService { idList.add(it.next()); } for (Integer iedId : idList) { - this.onlyStop(iedId); + this.stopCollect(iedId); } } @@ -131,14 +110,16 @@ public class RealTimeDataService { for (ModelNode child : fcnode.getChildren()) { if (child instanceof BasicDataAttribute) { BasicDataAttribute bda = (BasicDataAttribute) child; - processBdaNodeValue(bda); + StaticVariable.updateServerNodeValue(bda); + StaticVariable.updateLastData(bda); } else if (child instanceof ConstructedDataAttribute) { ConstructedDataAttribute cda = (ConstructedDataAttribute) child; if (!CollectionUtils.isEmpty(cda.getChildren())) { for (ModelNode cchild : cda.getChildren()) { if (cchild instanceof BasicDataAttribute) { BasicDataAttribute bda = (BasicDataAttribute) cchild; - processBdaNodeValue(bda); + StaticVariable.updateServerNodeValue(bda); + StaticVariable.updateLastData(bda); } } } @@ -148,13 +129,4 @@ public class RealTimeDataService { } } - private static void processBdaNodeValue(BasicDataAttribute bda) { - Iterator it = StaticVariable.iecServerMap.keySet().iterator(); - while (it.hasNext()) { - Integer key = it.next(); - IecServer iecServer = StaticVariable.iecServerMap.get(key); - iecServer.updateBda(bda); - } - IEDCollectService.updateLastData(bda); - } } diff --git a/src/main/java/com/xydl/cac/model/StaticVariable.java b/src/main/java/com/xydl/cac/model/StaticVariable.java index 7789776..e8baf76 100644 --- a/src/main/java/com/xydl/cac/model/StaticVariable.java +++ b/src/main/java/com/xydl/cac/model/StaticVariable.java @@ -1,14 +1,16 @@ package com.xydl.cac.model; +import com.fazecast.jSerialComm.SerialPort; +import com.beanit.iec61850bean.BasicDataAttribute; import com.xydl.cac.entity.Jg; import com.xydl.cac.entity.ModevType; import com.xydl.cac.entity.WarnRule; import com.xydl.cac.entity.Zsb; import com.xydl.cac.iec.IecClient; import com.xydl.cac.iec.IecServer; +import com.xydl.cac.util.DateUtil; -import java.util.HashMap; -import java.util.List; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class StaticVariable { @@ -19,6 +21,8 @@ public class StaticVariable { public static HashMap doneWarnMap = new HashMap<>(); public static HashMap realTimeClientMap = new HashMap<>(); public static int shutdown = 0; + public static HashMap rptFromActiveMap = new HashMap<>(); + public static HashMap rptToActiveMap = new HashMap<>(); public static HashMap unit_Cache = new HashMap<>(); public static List modevType_Cache = null; @@ -26,6 +30,8 @@ public class StaticVariable { public static List zsb_Cache = null; public static ConcurrentHashMap rule_Cache = new ConcurrentHashMap<>(); + + public static void wait(int seconds) throws InterruptedException { for (int i = 0; i < seconds; i++) { if (shutdown == 1) { @@ -34,4 +40,50 @@ public class StaticVariable { Thread.sleep(1000); } } + + // 更新服务端 + public static void updateServerNodeValue(BasicDataAttribute bda) { + Iterator it = StaticVariable.iecServerMap.keySet().iterator(); + while (it.hasNext()) { + Integer key = it.next(); + IecServer iecServer = StaticVariable.iecServerMap.get(key); + iecServer.updateBda(bda); + } + } + + // 更新最新数据缓存 + public static void updateLastData(Integer eqmid, String colname, String value, String time) { + HashMap map = StaticVariable.sensorLastDataMap.get(eqmid); + if (map == null) { + map = new HashMap<>(); + StaticVariable.sensorLastDataMap.put(eqmid, map); + } + map.put(colname, value); + if (time != null) { + map.put("acquisitionTime", time); + } + } + + // 更新最新数据缓存 + public static void updateLastData(BasicDataAttribute bda) { + try { + String ref = bda.getReference().toString(); + String key = ref + "_" + bda.getFc().toString(); + if (StaticVariable.paramRelationMap.containsKey(key)) { + String value = StaticVariable.paramRelationMap.get(key); + String[] str = value.split(","); + Integer eqmid = Integer.parseInt(str[0]); + String colname = str[1]; + value = bda.getValueString(); + if ("acquisitionTime".equals(colname)) { + value = DateUtil.fromZoneUTCToLocal(value); + if (value == null) { + return; + } + } + updateLastData(eqmid, colname, value, null); + } + } catch (Exception ignore) { + } + } } diff --git a/src/main/java/com/xydl/cac/serialport/DataListener.java b/src/main/java/com/xydl/cac/serialport/DataListener.java new file mode 100644 index 0000000..c46e87a --- /dev/null +++ b/src/main/java/com/xydl/cac/serialport/DataListener.java @@ -0,0 +1,39 @@ +package com.xydl.cac.serialport; + +import com.fazecast.jSerialComm.SerialPort; +import com.fazecast.jSerialComm.SerialPortDataListener; +import com.fazecast.jSerialComm.SerialPortEvent; +import com.xydl.cac.util.ByteUtil; +import lombok.SneakyThrows; +import org.apache.commons.compress.utils.ByteUtils; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketSession; + +public class DataListener implements SerialPortDataListener { + private WebSocketSession session; + private String portName; + + //通过websocket打开监听设备的时候绑定session返回给前端数据 + public DataListener(String portName) { + this.portName = portName; + } + + @Override + public int getListeningEvents() { + return SerialPort.LISTENING_EVENT_DATA_WRITTEN; + } + + @SneakyThrows + @Override + public void serialEvent(SerialPortEvent event) { + String hexString = ""; + if (event.getEventType() == SerialPort.LISTENING_EVENT_DATA_WRITTEN) { + byte[] newData = new byte[event.getSerialPort().bytesAvailable()]; + int numRead = event.getSerialPort().readBytes(newData, newData.length); + hexString = ByteUtil.bytesToHexString(newData); + } + System.out.println("监听接收串口" + portName + ";数据:" + hexString); + session.sendMessage(new TextMessage(hexString)); + } +} + diff --git a/src/main/java/com/xydl/cac/serialport/SerialPortServer.java b/src/main/java/com/xydl/cac/serialport/SerialPortServer.java new file mode 100644 index 0000000..0cd89d7 --- /dev/null +++ b/src/main/java/com/xydl/cac/serialport/SerialPortServer.java @@ -0,0 +1,151 @@ +package com.xydl.cac.serialport; + +import com.fazecast.jSerialComm.SerialPort; +import com.xydl.cac.model.StaticVariable; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import javax.annotation.PreDestroy; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Service +@Slf4j +public class SerialPortServer { + + @Value("${cac.warnport.name}") + public String portname; + + @Value("${cac.warnport.intervaltime:60}") + public Integer intervaltime; + + @Value("${cac.warnport.warntime:5}") + public Integer warntime; + + public SerialPort currentPort;//当前可用串口 + public long LastWarningTime;//最后一次硬接点告警时间 + public boolean started = false; + + byte[] openbuffer = new byte[]{00, (byte) 0xf1, (byte) 0xff};//发送串口告警 + byte[] stopbuffer = new byte[]{00, (byte) 0x01, (byte) 0xff};//关闭串口告警 + + public void discoverSerialPort() { + if (currentPort == null) { + List serialPortList = new ArrayList<>(); + SerialPort[] commPorts = SerialPort.getCommPorts(); + if (commPorts != null && commPorts.length > 0) { + serialPortList = Arrays.asList(commPorts); + for (SerialPort port : serialPortList) { + log.info("获取串口: " + port.getSystemPortName()); + String systemPortName = port.getSystemPortName(); + if (systemPortName != null) { + if (systemPortName.startsWith(portname)) { + currentPort = port; + log.info("获取到硬接点告警串口: " + port.getSystemPortName()); + } + } + } + } + } else { + log.error("硬接点串口存在!"); + } + } + + public void closeSerialPort() { + if (currentPort != null) { + log.info("断开串口成功!"); + currentPort.closePort(); + } else { + log.error("断开串口失败,没有对应的硬接点告警串口!"); + } + } + + + //发送数据到串口 + @Async + public void sendData() { + if (!started) { + started = true; + if (openSerialPort()) { + SerialPort port = currentPort; + if (port != null) { + long l = System.currentTimeMillis(); + if (LastWarningTime == 0) { + LastWarningTime = l; + } else { + if (l - LastWarningTime <= (intervaltime * 1000)) { + started = false; + log.info("告警频繁,取消告警!"); + return; + } + } + LastWarningTime = l; + log.info("开始发送告警!"); + port.writeBytes(openbuffer, openbuffer.length); + int seconds = 0; + while (StaticVariable.shutdown == 0 && seconds < warntime) { + try { + Thread.sleep(1000); + seconds++; + } catch (Exception ignore) { + } + } + log.info("开始关闭告警!"); + port.writeBytes(stopbuffer, stopbuffer.length); + + } + } + started = false; + closeSerialPort(); + } + } + + + public Boolean openSerialPort() { + discoverSerialPort(); + if (currentPort != null) { + if (currentPort.isOpen()) { + log.info("硬接点告警串口已经打开!"); + return true; + } else { + int baudRate = 9600; // 波特率 + int parity = SerialPort.EVEN_PARITY; // 校验位 + int dataBits = 8; // 数据位 + int stopBits = SerialPort.ONE_STOP_BIT; // 停止位 + try { + boolean setComResult = currentPort.setComPortParameters(baudRate, dataBits, stopBits, parity); // 设置参数 + boolean setComTimes = currentPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 20000, 0); // 设置超时 + if (setComResult && setComTimes) { + currentPort.addDataListener(new DataListener(currentPort.getSystemPortName())); + } + boolean b = currentPort.openPort(); + if (b) { + log.info("打开硬接点告警串口成功!"); + return true; + } else { + currentPort = null; + log.error("打开串口失败!"); + return false; + } + } catch (Exception e) { + e.printStackTrace(); + currentPort = null; + log.error("打开串口失败" + e.getMessage()); + return false; + } + } + } else { + log.error("打开串口失败,找不到硬接点串口!"); + return false; + } + } + + @PreDestroy + private void stop() { + closeSerialPort(); + } + +} diff --git a/src/main/java/com/xydl/cac/service/impl/DataServiceImpl.java b/src/main/java/com/xydl/cac/service/impl/DataServiceImpl.java index 5619341..29fa793 100644 --- a/src/main/java/com/xydl/cac/service/impl/DataServiceImpl.java +++ b/src/main/java/com/xydl/cac/service/impl/DataServiceImpl.java @@ -244,7 +244,7 @@ public class DataServiceImpl implements DataService { @Override public List> getLatestData(String tableName, Integer devId, List points, Date start) throws Exception { ConditionModel model = new ConditionModel(); - model.setPageSize(1000); + model.setPageSize(500); model.setPageNum(1); model.setStartTime(start); model.setExcludeStartTime(true); diff --git a/src/main/java/com/xydl/cac/service/impl/IcdFileConfigServiceImpl.java b/src/main/java/com/xydl/cac/service/impl/IcdFileConfigServiceImpl.java index 1a02435..fd91fe4 100644 --- a/src/main/java/com/xydl/cac/service/impl/IcdFileConfigServiceImpl.java +++ b/src/main/java/com/xydl/cac/service/impl/IcdFileConfigServiceImpl.java @@ -3,7 +3,9 @@ package com.xydl.cac.service.impl; import com.xydl.cac.entity.*; import com.xydl.cac.entity.constants.Constants; import com.xydl.cac.exception.BusinessException; +import com.xydl.cac.iec.IecClient; import com.xydl.cac.model.IcdAttUpdateModel; +import com.xydl.cac.model.StaticVariable; import com.xydl.cac.repository.*; import com.xydl.cac.service.DataService; import com.xydl.cac.service.IcdFileConfigService; @@ -40,6 +42,8 @@ public class IcdFileConfigServiceImpl implements IcdFileConfigService { RptparamindexRepository rptparamindexRepository; @Resource DataService dataService; + @Resource + IedDlConfigRepository iedDlConfigRepository; @Override public void upload(String xml, String filename, int srv) throws Exception { @@ -108,6 +112,15 @@ public class IcdFileConfigServiceImpl implements IcdFileConfigService { List iedList = iedRepository.findByIcdFileId(icdFile.getId()); for (IcdIed ied : iedList) { if (StringUtils.isNotBlank(ied.getIp())) { + ied.setConnected(false); + ied.setRetry(0); + ied.setSeconds(0); + IecClient iecClient = StaticVariable.realTimeClientMap.get(ied.getId()); + if (iecClient != null) { + ied.setRetry(iecClient.retry); + ied.setConnected(iecClient.connected); + ied.setSeconds(iecClient.seconds); + } result.add(ied); } } @@ -220,6 +233,7 @@ public class IcdFileConfigServiceImpl implements IcdFileConfigService { configRepository.deleteAll(); fileRepository.deleteAll(); iedRepository.deleteAll(); + iedDlConfigRepository.deleteAll(); } @Override diff --git a/src/main/java/com/xydl/cac/service/impl/IcdTransformServiceImpl.java b/src/main/java/com/xydl/cac/service/impl/IcdTransformServiceImpl.java index f4eadc1..3799fec 100644 --- a/src/main/java/com/xydl/cac/service/impl/IcdTransformServiceImpl.java +++ b/src/main/java/com/xydl/cac/service/impl/IcdTransformServiceImpl.java @@ -11,8 +11,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; -import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Optional; @@ -24,8 +22,6 @@ public class IcdTransformServiceImpl implements IcdTransformService { @Resource IcdTransformRepository transformRepository; - public static HashMap rptFromActiveMap = new HashMap<>(); - public static HashMap rptToActiveMap = new HashMap<>(); @Override @CacheEvict(cacheNames = {"listTransform"}, allEntries = true) diff --git a/src/main/java/com/xydl/cac/service/impl/IedDlConfigServiceImpl.java b/src/main/java/com/xydl/cac/service/impl/IedDlConfigServiceImpl.java index 0a80e7e..4e4c367 100644 --- a/src/main/java/com/xydl/cac/service/impl/IedDlConfigServiceImpl.java +++ b/src/main/java/com/xydl/cac/service/impl/IedDlConfigServiceImpl.java @@ -100,7 +100,8 @@ public class IedDlConfigServiceImpl implements IedDlConfigService { IcdFile icdFile = optionalFile.get(); IecClient iecClient = new IecClient(); try { - iecClient.connect(ied, icdFile.getXml()); + iecClient.init(ied, icdFile.getXml()); + iecClient.connect(); return iecClient.listFile(path); } catch (Exception ex) { throw new BusinessException(ex.getMessage()); diff --git a/src/main/java/com/xydl/cac/service/impl/WarnRuleServiceImpl.java b/src/main/java/com/xydl/cac/service/impl/WarnRuleServiceImpl.java index dd00896..acdeec2 100644 --- a/src/main/java/com/xydl/cac/service/impl/WarnRuleServiceImpl.java +++ b/src/main/java/com/xydl/cac/service/impl/WarnRuleServiceImpl.java @@ -86,6 +86,7 @@ public class WarnRuleServiceImpl implements WarnRuleService { rule.setThreshold(item.getThreshold()); rule.setLevel(item.getLevel()); rule.setActive(item.getActive()); + rule.setNotifyCom(item.getNotifyCom()); repository.save(rule); StaticVariable.rule_Cache.remove(rule.getId()); } diff --git a/src/main/java/com/xydl/cac/task/RuleCheckTask.java b/src/main/java/com/xydl/cac/task/RuleCheckTask.java index d7a7b5d..148d448 100644 --- a/src/main/java/com/xydl/cac/task/RuleCheckTask.java +++ b/src/main/java/com/xydl/cac/task/RuleCheckTask.java @@ -4,10 +4,12 @@ import com.xydl.cac.entity.ModevTypePoint; import com.xydl.cac.entity.NSensor; import com.xydl.cac.entity.WarnRule; import com.xydl.cac.entity.Warning; +import com.xydl.cac.entity.constants.Constants; import com.xydl.cac.model.StaticVariable; import com.xydl.cac.model.TriggerModel; import com.xydl.cac.repository.WarnRuleRepository; import com.xydl.cac.repository.WarningRepository; +import com.xydl.cac.serialport.SerialPortServer; import com.xydl.cac.service.DataService; import com.xydl.cac.socket.WebSocketServer; import com.xydl.cac.util.DateUtil; @@ -33,6 +35,8 @@ public class RuleCheckTask { DingTalkPushUtil dingTalkPushUtil; @Resource WebSocketServer webSocketServer; + @Resource + SerialPortServer serialPortServer; int shutdown = 0; @@ -73,6 +77,10 @@ public class RuleCheckTask { for (TriggerModel model : warnList) { this.sendWarning(rule, model); } + if (rule.getNotifyCom() != null && rule.getNotifyCom().intValue() == Constants.TRUE) { + // 通知串口 + serialPortServer.sendData(); + } } } catch (Exception e) { log.error("RuleCheckTask.ruleCheck error.", e); diff --git a/src/main/java/com/xydl/cac/transform/I2DataTransformer.java b/src/main/java/com/xydl/cac/transform/I2DataTransformer.java index f355a8e..3dab3fe 100644 --- a/src/main/java/com/xydl/cac/transform/I2DataTransformer.java +++ b/src/main/java/com/xydl/cac/transform/I2DataTransformer.java @@ -1,6 +1,5 @@ package com.xydl.cac.transform; -import com.alibaba.excel.util.StringUtils; import com.xydl.cac.entity.*; import com.xydl.cac.model.StaticVariable; import com.xydl.cac.model.i2sync.Attr; @@ -9,12 +8,10 @@ import com.xydl.cac.model.i2sync.Monitordata; import com.xydl.cac.model.i2sync.Request; import com.xydl.cac.util.DateUtil; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; @Component @Slf4j @@ -34,23 +31,42 @@ public class I2DataTransformer { } } + LinkedHashMap> fieldMap = this.sortFieldList(fieldList); + List nodeList = new ArrayList<>(); for (Map map : dataList) { - String date = (String) map.get("acquisitionTime"); - Datanode node = new Datanode(); - node.setSensorid(sensor.getSensorCode()); - node.setEquipmentid(sensor.getEquipmentId()); - node.setTimestamp(date); - List attrs = new ArrayList<>(); - Attr attr = new Attr(); - attr.setName("Phase"); - attr.setValue(sensor.getPhase()); - attr.setAlarm("FALSE"); - attrs.add(attr); - for (I2syncField field : fieldList) { - Object value = map.get(field.getFieldName()); - attr = new Attr(); + Iterator fit = fieldMap.keySet().iterator(); + while (fit.hasNext()) { + String attach = fit.next(); + List fieldListNew = fieldMap.get(attach); + + Datanode node = this.buildDatanode(sensor, config.getTypeCode(), attach, + fieldListNew, map, ruleList); + if (node != null) { + nodeList.add(node); + record.setLastDTime(DateUtil.parse(node.getTimestamp())); + } + } + } + + Monitordata monitordata = new Monitordata(); + monitordata.setCacid(sensor.getSensorCode()); + monitordata.setDatanodenum(nodeList.size()); + monitordata.setDatanode(nodeList); + Request request = new Request(); + request.setMonitordata(monitordata); + return request; + } + + private Datanode buildDatanode(NSensor sensor, String typeCode, String attach, + List fieldList, Map dataMap, + List ruleList) { + List attrs = new ArrayList<>(); + for (I2syncField field : fieldList) { + Object value = dataMap.get(field.getFieldName()); + if (value != null) { + Attr attr = new Attr(); attr.setName(field.getDestFieldName()); attr.setValue(String.valueOf(value)); if (this.triggerRule(ruleList, field.getFieldName(), value)) { @@ -58,24 +74,63 @@ public class I2DataTransformer { } else { attr.setAlarm("FALSE"); } - if (StringUtils.isBlank(node.getType())) { - node.setType(config.getTypeCode()); - } attrs.add(attr); } - node.setAttr(attrs); + } + if (attrs.size() < 1) { + return null; + } + String date = (String) dataMap.get("acquisitionTime"); + Datanode node = new Datanode(); + node.setType(typeCode); + node.setTimestamp(date); + node.setAttr(attrs); - nodeList.add(node); - record.setLastDTime(DateUtil.parse(date)); + Attr attr = new Attr(); + attr.setName("Phase"); + attr.setAlarm("FALSE"); + attrs.add(attr); + if (StringUtils.isBlank(attach)) { + attr.setValue(sensor.getPhase()); + node.setSensorid(sensor.getSensorCode()); + node.setEquipmentid(sensor.getEquipmentId()); + } else { + attr.setValue(""); + String code = sensor.getSensorCode(); + node.setSensorid(code); + if (code != null && code.length() > attach.length() + 2) { + int len = code.length() - 2; + String tail = code.substring(len); + String first = code.substring(0, len - attach.length()); + node.setSensorid(first + attach + tail); + } + String equipmentid = sensor.getEquipmentId(); + node.setEquipmentid(equipmentid); + if (equipmentid != null && equipmentid.length() > attach.length() + 2) { + int len = equipmentid.length() - 2; + String tail = equipmentid.substring(len); + String first = equipmentid.substring(0, len - attach.length()); + node.setEquipmentid(first + attach + tail); + } } + return node; + } - Monitordata monitordata = new Monitordata(); - monitordata.setCacid(sensor.getSensorCode()); - monitordata.setDatanodenum(nodeList.size()); - monitordata.setDatanode(nodeList); - Request request = new Request(); - request.setMonitordata(monitordata); - return request; + private LinkedHashMap> sortFieldList(List fieldList) { + LinkedHashMap> map = new LinkedHashMap<>(); + for (I2syncField item : fieldList) { + String attach = item.getAttach(); + if (attach == null) { + attach = ""; + } + List list = map.get(attach); + if (list == null) { + list = new ArrayList<>(); + map.put(attach, list); + } + list.add(item); + } + return map; } private boolean triggerRule(List ruleList, String fieldName, Object value) { diff --git a/src/main/java/com/xydl/cac/util/ByteUtil.java b/src/main/java/com/xydl/cac/util/ByteUtil.java new file mode 100644 index 0000000..244bddf --- /dev/null +++ b/src/main/java/com/xydl/cac/util/ByteUtil.java @@ -0,0 +1,377 @@ +package com.xydl.cac.util; + +import java.io.IOException; +import java.math.BigInteger; +import java.net.Socket; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.springframework.util.StringUtils; + +public class ByteUtil { + public static byte[] uintToBytes(long value) { + byte[] src = new byte[4]; + src[3] = ((byte) (int) (value >> 24 & 0xFF)); + src[2] = ((byte) (int) (value >> 16 & 0xFF)); + src[1] = ((byte) (int) (value >> 8 & 0xFF)); + src[0] = ((byte) (int) (value & 0xFF)); + return src; + } + + public static byte[] uint16ToBytes(int value) { + byte[] src = new byte[2]; + src[1] = ((byte) (value >> 8 & 0xFF)); + src[0] = ((byte) (value & 0xFF)); + return src; + } + + public static byte[] uint8ToBytes(short value) { + byte[] src = new byte[1]; + src[0] = ((byte) (value & 0xFF)); + return src; + } + + /** + * ascii 转 十六进制 + * + * @param str + * @return + */ + public static String convertStringToHex(String str) { + + char[] chars = str.toCharArray(); + + StringBuffer hex = new StringBuffer(); + for (int i = 0; i < chars.length; i++) { + hex.append(Integer.toHexString((int) chars[i])); + } + + return hex.toString(); + } + + /** + * 十六进制转 ascii + * + * @param hex + * @return + */ + public static String convertHexToString(String hex) { + + StringBuilder sb = new StringBuilder(); + StringBuilder temp = new StringBuilder(); + + // 49204c6f7665204a617661 split into two characters 49, 20, 4c... + for (int i = 0; i < hex.length() - 1; i += 2) { + + // grab the hex in pairs + String output = hex.substring(i, (i + 2)); + // convert hex to decimal + int decimal = Integer.parseInt(output, 16); + // convert the decimal to character + sb.append((char) decimal); + + temp.append(decimal); + } + + return sb.toString(); + } + + /** + * 十六进制字符串高低位互换 + *

+ * 如:12345678 -> 78563412 + * 00 5f 8d c2 + * c28d5f00 + * + * @param str + * @return float + */ + public static float hexStrTofloat(String str) { + try { + String s = str.substring(6, 8) + str.substring(4, 6) + str.substring(2, 4) + str.substring(0, 2); + return Float.intBitsToFloat(new BigInteger(s, 16).intValue()); + } catch (NumberFormatException e) { + e.printStackTrace(); + System.err.println("errrrr.."); + return 0L; + } + } + + public static float hexStrTofloat1(String str) { + try { + int i = Integer.parseInt(str, 16); + byte byte4 = (byte) (i & 0xff); + byte byte3 = (byte) ((i & 0xff00) >> 8); + byte byte2 = (byte) ((i & 0xff0000) >> 16); + byte byte1 = (byte) ((i & 0xff000000) >> 24); // 拼装成 "高字节在后,低字节在前"的格式 + int realint = (byte1 & 0xff) << 0 | (byte2 & 0xff) << 8 | (byte3 & 0xff) << 16 | (byte4 & 0xff) << 24; + return Float.intBitsToFloat(realint); + } catch (NumberFormatException e) { + System.err.println("errrrr.."); + return 0L; + } + + } + + public static int bytesToInt(byte[] src, int startPos) { + if ((src == null) || (src.length <= 0) || (src.length < startPos + 4) || (startPos < 0)) { + return -1; + } + int result = (int) ((src[(startPos + 3)] & 0xFF) * 16777216 + (src[(startPos + 2)] & 0xFF) * 65536L + + (src[(startPos + 1)] & 0xFF) * 256L + (src[startPos] & 0xFF)); + return result; + } + + public static int bytesToIntHL(byte[] src, int startPos, int len) { + if ((src == null) || (src.length <= 0) || (src.length < startPos + len) || (startPos < 0)) { + return -1; + } + int result = 0; + for (int i = 0; i < len; i++) { + result += (int) ((src[(startPos + i)] & 0xFF) * (1 << (len - 1 - i) * 8)); + } + return result; + } + + public static void printHexString(byte[] b) { + for (int i = 0; i < b.length; i++) { + String hex = Integer.toHexString(b[i] & 0xFF); + if (hex.length() == 1) { + hex = '0' + hex; + } + System.out.print(hex.toUpperCase() + " "); + } + System.out.println(); + } + + /** + * 字节数组转为十六进制字符串 + * + * @param src + * @return + */ + public static String bytesToHexString(byte[] src) { + StringBuilder stringBuilder = new StringBuilder(""); + if ((src == null) || (src.length <= 0)) { + return null; + } + for (int i = 0; i < src.length; i++) { + int v = src[i] & 0xFF; + String hv = Integer.toHexString(v); + if (hv.length() < 2) { + stringBuilder.append(0); + } + stringBuilder.append(hv); + } + return stringBuilder.toString(); + } + + public static String bytesToDecString(byte[] src) { + if ((src == null) || (src.length <= 0)) { + return null; + } + int result = (int) ((src[3] & 0xFF) * 16777216 + (src[2] & 0xFF) * 65536L + (src[1] & 0xFF) * 256L + + (src[0] & 0xFF)); + return Integer.toString(result); + } + + public static String bytesToHexString(byte[] src, int len) { + StringBuilder stringBuilder = new StringBuilder(""); + StringBuilder temp = new StringBuilder(""); + if ((src == null) || (src.length <= 0)) { + return null; + } + for (int i = 0; i < src.length; i++) { + int v = src[i] & 0xFF; + if (v != 0) { + String hv = Integer.toHexString(v); + StringBuilder temp1 = new StringBuilder(""); + if (hv.length() < 2) { + temp1.append(0); + } + temp1.append(hv); + temp1.append(temp); + temp = temp1; + } + } + if (len / 2 > temp.length()) { + String result = temp.toString(); + for (int k = 0; k < (len - result.length()) / 2; k++) { + stringBuilder.append("00"); + } + stringBuilder.append(result); + } else { + stringBuilder = temp; + } + return stringBuilder.toString(); + } + + public static String bytesToDecString(byte[] src, int len) { + if ((src == null) || (src.length <= 0)) { + return null; + } + int result = (int) (src[3] * 16777216 + src[2] * 65536L + src[1] * 256L + src[0]); + String temp = Integer.toString(result); + if (temp.length() < len) { + StringBuilder finalString = new StringBuilder(""); + for (int k = 0; k < len - temp.length(); k++) { + finalString.append(0); + } + finalString.append(result); + return finalString.toString(); + } + return temp; + } + + public static float byte2float(byte[] b, int index) { + int l = b[(index + 0)]; + l &= 0xFF; + l = (int) (l | b[(index + 1)] << 8); + l &= 0xFFFF; + l = (int) (l | b[(index + 2)] << 16); + l &= 0xFFFFFF; + l = (int) (l | b[(index + 3)] << 24); + return Float.intBitsToFloat(l); + } + + public static int ASCIIToInt(byte[] b, int len) { + int result = 0; + for (int i = 0; i < len; i++) { + char temp = (char) b[i]; + int i_temp; + switch (temp) { + case 'A': + i_temp = 10; + break; + case 'B': + i_temp = 11; + break; + case 'C': + i_temp = 12; + break; + case 'D': + i_temp = 13; + break; + case 'E': + i_temp = 14; + break; + case 'F': + i_temp = 15; + break; + default: + i_temp = Integer.valueOf(temp).intValue(); + } + result = i_temp + result * 16; + } + return result; + } + + public static String ASCIIToString(byte[] b, int len) { + String result = ""; + for (int i = 0; i < len; i++) { + result = result + (char) b[i]; + } + return result; + } + + + /** + * 将16进制字符串转换为byte[] + * + * @param str + * @return + */ + public static byte[] toBytes(String str) { + if (str == null || str.trim().equals("")) { + return new byte[0]; + } + + byte[] bytes = new byte[str.length() / 2]; + for (int i = 0; i < str.length() / 2; i++) { + String subStr = str.substring(i * 2, i * 2 + 2); + bytes[i] = (byte) Integer.parseInt(subStr, 16); + } + + return bytes; + } + + + /** + * 带符号的16进制字符串转float + */ + public static float SigneHexToFloat(String str) { + String s = str.substring(2, 4) + str.substring(0, 2); + float x = (float) Integer.valueOf(s, 16).shortValue(); + return x; + } + + /** + * 有符号16进制转10进制 + * + * @param strHex + * @return + */ + public static int signedHexToDec(String strHex) { + if (strHex.length() == 0) { + return 0; + } + int x = 0; + //带符号十六进制转换十进制 + String fristNum = strHex.substring(0, 1); + String hexStr2Byte = parseHexStr2Byte(fristNum); + String flag = hexStr2Byte.substring(0, 1); + if ("1".equals(flag)) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < strHex.length(); i++) { + String num = strHex.substring(i, i + 1); + int decNum = Integer.parseInt(num, 16); + int a = decNum ^ 15; + sb.append(intToHex(a)); + } + x = -Integer.parseInt(sb.toString(), 16) - 1; + } else { + x = Integer.parseInt(strHex, 16); + } + + return x; + + } + + //十进制转16进制 + private static String intToHex(int n) { + StringBuffer s = new StringBuffer(); + String a; + char[] b = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + while (n != 0) { + s = s.append(b[n % 16]); + n = n / 16; + } + a = s.reverse().toString(); + return a; + } + + /** + * 将16进制转换为二进制 + * + * @param hexStr + * @return + */ + public static String parseHexStr2Byte(String hexStr) { + if (hexStr.length() == 0) { + return null; + } + int sint = Integer.valueOf(hexStr, 16); + //十进制在转换成二进制的字符串形式输出! + String bin = Integer.toBinaryString(sint); + for (int i = bin.length(); i < 4; i++) { + bin = "0" + bin; + } + return bin; + } +} + diff --git a/src/main/java/com/xydl/cac/util/DateUtil.java b/src/main/java/com/xydl/cac/util/DateUtil.java index d033d15..9825e48 100644 --- a/src/main/java/com/xydl/cac/util/DateUtil.java +++ b/src/main/java/com/xydl/cac/util/DateUtil.java @@ -1,5 +1,7 @@ package com.xydl.cac.util; +import lombok.extern.slf4j.Slf4j; + import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.*; @@ -8,6 +10,7 @@ import java.time.temporal.ChronoUnit; import java.util.Calendar; import java.util.Date; +@Slf4j public class DateUtil { public final static String defaultDatePattern = "yyyy-MM-dd HH:mm:ss"; public static DateTimeFormatter defaultFormatter = DateTimeFormatter.ofPattern(defaultDatePattern); @@ -109,6 +112,9 @@ public class DateUtil { Date date = parse(time); time = format(date); LocalDateTime localtime = LocalDateTime.parse(time, defaultFormatter); + if (localtime.getYear() < 2000) { + return null; + } ZonedDateTime zonedDateTime = localtime.atZone(ZoneOffset.UTC); ZonedDateTime convertedDateTime = zonedDateTime.withZoneSameInstant(ZoneId.systemDefault()); String result = convertedDateTime.format(defaultFormatter); diff --git a/src/main/java/com/xydl/cac/util/IcdXmlUtil.java b/src/main/java/com/xydl/cac/util/IcdXmlUtil.java index c59961a..5da9067 100644 --- a/src/main/java/com/xydl/cac/util/IcdXmlUtil.java +++ b/src/main/java/com/xydl/cac/util/IcdXmlUtil.java @@ -98,6 +98,13 @@ public class IcdXmlUtil { String lnInst = fcdaNode.get("lnInst").asText(); String doName = fcdaNode.get("doName").asText(); String fc = fcdaNode.get("fc").asText(); + JsonNode preNode = fcdaNode.get("prefix"); + if (preNode != null) { + String prefix = preNode.asText(); + if (StringUtils.isNotBlank(prefix)) { + lnClass = prefix + lnClass; + } + } JsonNode lnNode = mapLN.get(lnClass + lnInst); String lnType = lnNode.get("lnType").asText(); @@ -154,6 +161,13 @@ public class IcdXmlUtil { for (JsonNode node : list) { String lnClass = node.get("lnClass").asText(); String inst = node.get("inst").asText(); + JsonNode preNode = node.get("prefix"); + if (preNode != null) { + String prefix = preNode.asText(); + if (StringUtils.isNotBlank(prefix)) { + lnClass = prefix + lnClass; + } + } map.put(lnClass + inst, node); } return map; diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index ef5c1d6..e3ccde9 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -40,7 +40,7 @@ spring: cac: datapath: /home/xydl/ncac/data 61850: - enable: true + enable: false i2: enable: false url: http://192.168.1.190:8080/busi-back-ws/service/XydlService @@ -49,3 +49,7 @@ cac: token: e65e730cba22e320e16926fd4ff19ce787fa2162d065792bb6562c6d4a4cf328 secret: SEC72e5fb1b4ce7f9fed55386040d599035c50f8d2a181ad66bd1277549f0716124 rsakey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y= + warnport: + name: ttyCH341USB0 + intervaltime: 60 + warntime: 5 diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 33cd6df..b9815c4 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -49,3 +49,7 @@ cac: token: e65e730cba22e320e16926fd4ff19ce787fa2162d065792bb6562c6d4a4cf328 secret: SEC72e5fb1b4ce7f9fed55386040d599035c50f8d2a181ad66bd1277549f0716124 rsakey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y= + warnport: + name: ttyCH341USB0 + intervaltime: 60 + warntime: 5 \ No newline at end of file