Commit 723cd832 authored by duanruiming's avatar duanruiming

[update] 优化海信灯态数据;添加海信TCP协议;

parent 90c413f7
package net.wanji.utc.hisense; package net.wanji.utc.hisense;
import net.wanji.utc.hisense.netty.TcpClient;
import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner; import org.springframework.boot.CommandLineRunner;
...@@ -33,6 +32,6 @@ public class HisenseApplication implements CommandLineRunner { ...@@ -33,6 +32,6 @@ public class HisenseApplication implements CommandLineRunner {
@Override @Override
public void run(String... args) throws Exception { public void run(String... args) throws Exception {
//UdpClient.connection(localPort, remoteProt); //UdpClient.connection(localPort, remoteProt);
TcpClient.connection(remoteIp, remoteProt); //TcpClient.connection(remoteIp, remoteProt);
} }
} }
...@@ -36,6 +36,6 @@ public enum DataBrainControlModeEnum { ...@@ -36,6 +36,6 @@ public enum DataBrainControlModeEnum {
return value.getWjControl(); return value.getWjControl();
} }
} }
return null; return 11; // 默认定周期
} }
} }
package net.wanji.utc.hisense.netty; package net.wanji.utc.hisense.netty;
import cn.hutool.core.util.HexUtil;
import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.wanji.utc.hisense.cache.CrossInfoCache;
import net.wanji.utc.hisense.cache.netty.NettyMessageCache;
import net.wanji.utc.hisense.common.enums.xml.MessageTypeEnum;
import net.wanji.utc.hisense.netty.codec.MessageDecoder;
import net.wanji.utc.hisense.netty.codec.MessageEnCoder;
import net.wanji.utc.hisense.netty.handler.TcpClientHandler; import net.wanji.utc.hisense.netty.handler.TcpClientHandler;
import net.wanji.utc.hisense.pojo.netty.MessageResultPojo;
import net.wanji.utc.hisense.pojo.xml.pojo.messagecontent.HeartBeatRequest;
import net.wanji.utc.hisense.util.XMLUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.net.InetSocketAddress;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/** /**
* @author duanruiming * @author duanruiming
* @date 2024/01/08 17:33 * @date 2024/01/08 17:33
...@@ -18,6 +39,10 @@ import org.springframework.stereotype.Component; ...@@ -18,6 +39,10 @@ import org.springframework.stereotype.Component;
@Slf4j @Slf4j
@Component @Component
public class TcpClient { public class TcpClient {
private static ChannelFuture tcpChannelFuture = null;
@Resource(name = "commonThreadPoolExecutor")
private ThreadPoolTaskExecutor commonThreadPoolExecutor;
public static void connection(String host, int port) throws Exception { public static void connection(String host, int port) throws Exception {
EventLoopGroup group = new NioEventLoopGroup(); // 创建线程组 EventLoopGroup group = new NioEventLoopGroup(); // 创建线程组
try { try {
...@@ -29,15 +54,78 @@ public class TcpClient { ...@@ -29,15 +54,78 @@ public class TcpClient {
protected void initChannel(Channel ch) throws Exception { protected void initChannel(Channel ch) throws Exception {
//ch.pipeline().addLast(new XmlMessageDecoder()); // 添加自定义的解码器 //ch.pipeline().addLast(new XmlMessageDecoder()); // 添加自定义的解码器
//ch.pipeline().addLast(new XmlMessageEncoder()); // 添加自定义的编码器 //ch.pipeline().addLast(new XmlMessageEncoder()); // 添加自定义的编码器
ch.pipeline().addLast(new MessageDecoder());
ch.pipeline().addLast(new MessageEnCoder());
ch.pipeline().addLast(new TcpClientHandler()); // 添加自定义的处理器 ch.pipeline().addLast(new TcpClientHandler()); // 添加自定义的处理器
} }
}); });
// 启动客户端,连接到服务器端,并同步,生成ChannelFuture对象 // 启动客户端,连接到服务器端,并同步,生成ChannelFuture对象
ChannelFuture f = b.connect(host, port).sync(); ChannelFuture f = b.connect(host, port).sync();
tcpChannelFuture = f;
// 对关闭通道进行监听 // 对关闭通道进行监听
f.channel().closeFuture().sync(); f.channel().closeFuture().sync();
} finally { } finally {
group.shutdownGracefully(); // 关闭线程组 group.shutdownGracefully(); // 关闭线程组
} }
} }
public static void sendMessage(String ip, Integer port, String msg) {
byte[] bytes = HexUtil.decodeHex(msg);
try {
if (tcpChannelFuture == null) {
return;
}
tcpChannelFuture.channel()
.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(bytes), new InetSocketAddress(ip, port))).sync();
log.debug("发送信号机:{}/{}命令消息:{}", ip, port, msg);
} catch (InterruptedException e) {
log.error("sendMsg is error", e);
}
}
public static MessageResultPojo sendMessage(String ip, Integer port, String msg, String command, int timeout) {
try {
if (timeout > 0) {
CountDownLatch countDownLatch = new CountDownLatch(1);
String key = StringUtils.join("/", ip, ":", port, "/", command);
long now = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
MessageResultPojo messageResultPojo = new MessageResultPojo(command, countDownLatch, now, timeout, null);
NettyMessageCache.NETTY_RESULT_TIMEOUT_MAP.put(key, messageResultPojo);
NettyMessageCache.COMMAND_RESULT_SIGN_MAP.put(key, CrossInfoCache.getCrossInfoByIp(ip));
sendMessage(ip, port, msg);
countDownLatch.await(timeout, TimeUnit.MILLISECONDS);
return NettyMessageCache.NETTY_RESULT_TIMEOUT_MAP.remove(key);
}
} catch (InterruptedException e) {
log.error("sendMsg is error", e);
}
return null;
}
@Scheduled(fixedRate = 300)
public void checkWaitTimeout() {
long now = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
NettyMessageCache.NETTY_RESULT_TIMEOUT_MAP.forEach((k, v) -> {
commonThreadPoolExecutor.execute(() -> {
if (now - v.getStartTime() > v.getWaitMillisecond()) {
log.warn("wait {}ms [{}] timeout", v.getWaitMillisecond(), k);
v.getCountDownLatch().countDown();
}
});
});
}
@Scheduled(fixedRate = 1000 * 20)
public void hearBeat() throws Exception {
try {
HeartBeatRequest heartBeatRequest = new HeartBeatRequest();
heartBeatRequest.setMessageType(MessageTypeEnum.HEARTBEAT_STATUS.getType());
log.error("心跳消息:{}", XMLUtils.convertToXml(heartBeatRequest));
tcpChannelFuture.channel().writeAndFlush(XMLUtils.strToHex(XMLUtils.convertToXml(heartBeatRequest)));
} catch (Exception e) {
log.error("每20秒心跳发送失败:", e);
throw new Exception(e);
}
}
} }
package net.wanji.utc.hisense.netty.commandsign; package net.wanji.utc.hisense.netty.commandsign;
import com.alibaba.fastjson.JSON;
import net.wanji.utc.hisense.pojo.convert.RunningLightsStatusPojo; import net.wanji.utc.hisense.pojo.convert.RunningLightsStatusPojo;
import net.wanji.utc.hisense.util.XMLUtils;
/** /**
* @author duanruiming * @author duanruiming
...@@ -9,9 +9,9 @@ import net.wanji.utc.hisense.pojo.convert.RunningLightsStatusPojo; ...@@ -9,9 +9,9 @@ import net.wanji.utc.hisense.pojo.convert.RunningLightsStatusPojo;
*/ */
public class CommandResultSign { public class CommandResultSign {
public static Object getHexSign(String data) { public static Object getHexSign(String data) throws Exception{
Object runningLightsStatusPojo = JSON.parseObject(data, RunningLightsStatusPojo.class); //Object runningLightsStatusPojo = JSON.parseObject(data, RunningLightsStatusPojo.class);
return runningLightsStatusPojo; return XMLUtils.convertXmlStrToObject(RunningLightsStatusPojo.class, data);
} }
} }
...@@ -21,6 +21,7 @@ import org.springframework.stereotype.Component; ...@@ -21,6 +21,7 @@ import org.springframework.stereotype.Component;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
...@@ -32,6 +33,12 @@ import java.util.Objects; ...@@ -32,6 +33,12 @@ import java.util.Objects;
@Component @Component
public class TcpClientHandler extends SimpleChannelInboundHandler<DatagramPacket> { public class TcpClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
log.info("海信服务连接成功:{}", ctx.channel());
ctx.fireChannelActive();
}
/** /**
* 读取消息 * 读取消息
* *
...@@ -94,4 +101,10 @@ public class TcpClientHandler extends SimpleChannelInboundHandler<DatagramPacket ...@@ -94,4 +101,10 @@ public class TcpClientHandler extends SimpleChannelInboundHandler<DatagramPacket
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
} }
public static void main(String[] args) {
Date date = new Date(1705024396764L);
System.err.println(date);
}
} }
\ No newline at end of file
...@@ -24,8 +24,8 @@ public class SystemScriptionRequest implements Serializable { ...@@ -24,8 +24,8 @@ public class SystemScriptionRequest implements Serializable {
// 实体类属性 // 实体类属性
// 子系统,海信接口服务器向外部系统发送时为Hisense // 子系统,海信接口服务器向外部系统发送时为Hisense
@XmlElement(name = "subSystem", defaultValue = "") @XmlElement(name = "subSystem", defaultValue = "Hisense")
private String subSystem; private String subSystem = "Hisense";
/** /**
* {@link MessageTypeEnum} * {@link MessageTypeEnum}
*/ */
...@@ -33,18 +33,18 @@ public class SystemScriptionRequest implements Serializable { ...@@ -33,18 +33,18 @@ public class SystemScriptionRequest implements Serializable {
private int messageType; private int messageType;
// 1-请求 0-应答 // 1-请求 0-应答
@XmlElement(name = "isRequest", defaultValue = "") @XmlElement(name = "isRequest", defaultValue = "")
private String isRequest; private String isRequest = "";
// seq唯一,长度固定20, 采用YYYYMMDDHHMMSS + 6位顺序号,不足前补0 // seq唯一,长度固定20, 采用YYYYMMDDHHMMSS + 6位顺序号,不足前补0
@XmlElement(name = "seq", defaultValue = "") @XmlElement(name = "seq", defaultValue = "")
private String seq; private String seq;
// 是否需要应答,1-需要 0-不需要 // 是否需要应答,1-需要 0-不需要
@XmlElement(name = "needResponse", defaultValue = "") @XmlElement(name = "needResponse", defaultValue = "")
private int needResponse; private String needResponse = "";
// 针对所有消息, 1-成功 0-失败 // 针对所有消息, 1-成功 0-失败
@XmlElement(name = "result", defaultValue = "") @XmlElement(name = "result", defaultValue = "")
private String result; private String result = "";
// 保留 // 保留
@XmlElement(name = "flag", defaultValue = "") @XmlElement(name = "flag", defaultValue = "")
private boolean flag; private String flag = "";
} }
...@@ -16,7 +16,7 @@ import javax.xml.bind.annotation.XmlRootElement; ...@@ -16,7 +16,7 @@ import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "systemScription") @XmlRootElement(name = "systemScription")
public class HeartBeatRequest extends SystemScriptionRequest { public class HeartBeatRequest extends SystemScriptionRequest {
private HeartBeatContent messageContent; private HeartBeatContent messageContent = new HeartBeatContent();
@Data @Data
public static class HeartBeatContent { public static class HeartBeatContent {
} }
......
...@@ -20,6 +20,7 @@ import net.wanji.utc.hisense.pojo.convert.HisenseLightStatusPojo; ...@@ -20,6 +20,7 @@ import net.wanji.utc.hisense.pojo.convert.HisenseLightStatusPojo;
import net.wanji.utc.hisense.pojo.dto.CrossSchemePhaseCountDownDTO; import net.wanji.utc.hisense.pojo.dto.CrossSchemePhaseCountDownDTO;
import net.wanji.utc.hisense.pojo.dto.PhaseCountDownDTO; import net.wanji.utc.hisense.pojo.dto.PhaseCountDownDTO;
import net.wanji.utc.hisense.service.SignalStatusService; import net.wanji.utc.hisense.service.SignalStatusService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
...@@ -160,6 +161,7 @@ public class SignalStatusServiceImpl implements SignalStatusService { ...@@ -160,6 +161,7 @@ public class SignalStatusServiceImpl implements SignalStatusService {
int runTime = period - cycleCountDown; int runTime = period - cycleCountDown;
int planId = (content.getPlanId() + 2) / 3; int planId = (content.getPlanId() + 2) / 3;
lightsStatusVO.setCrossId(crossId); lightsStatusVO.setCrossId(crossId);
lightsStatusVO.setCode(crossInfo.getCode());
lightsStatusVO.setSchemeId(String.valueOf(planId)); lightsStatusVO.setSchemeId(String.valueOf(planId));
String runMode = String.valueOf(DataBrainControlModeEnum.getWjControlMode(hiControlMode)); String runMode = String.valueOf(DataBrainControlModeEnum.getWjControlMode(hiControlMode));
lightsStatusVO.setRunMode(runMode); lightsStatusVO.setRunMode(runMode);
...@@ -173,8 +175,9 @@ public class SignalStatusServiceImpl implements SignalStatusService { ...@@ -173,8 +175,9 @@ public class SignalStatusServiceImpl implements SignalStatusService {
lightsStatusVO.setManufacturerCode("Hisense"); lightsStatusVO.setManufacturerCode("Hisense");
lightsStatusVO.setPhasePlanId(String.valueOf(planId)); lightsStatusVO.setPhasePlanId(String.valueOf(planId));
List<CrossSchemePhaseCountDownDTO> crossSchemePhaseCountDownList = CrossSchemePhaseTimeCountCache.crossSchemePhaseCountDownList; List<CrossSchemePhaseCountDownDTO> crossSchemePhaseCountDownList = CrossSchemePhaseTimeCountCache.crossSchemePhaseCountDownList;
setLightsStatusVOPhaseNoAndCountDown(lightsStatusVO, crossId, runTime, planId, crossSchemePhaseCountDownList); LightsStatusVO lightsStatusVOCurrent = setLightsStatusVOPhaseNoAndCountDown(lightsStatusVO, crossId, runTime, planId, crossSchemePhaseCountDownList);
SignalDataCache.runningStateInfoCacheNoLamp.put(crossId, lightsStatusVO); log.error("周期倒计时值:{}", crossId + lightsStatusVOCurrent.getCyclePhaseCountDown());
SignalDataCache.runningStateInfoCacheNoLamp.put(crossId, lightsStatusVOCurrent);
} }
} }
} }
...@@ -189,8 +192,9 @@ public class SignalStatusServiceImpl implements SignalStatusService { ...@@ -189,8 +192,9 @@ public class SignalStatusServiceImpl implements SignalStatusService {
* @param planId * @param planId
* @param crossSchemePhaseCountDownList * @param crossSchemePhaseCountDownList
*/ */
private static void setLightsStatusVOPhaseNoAndCountDown(LightsStatusVO lightsStatusVO, String crossId, int runTime, int planId, List<CrossSchemePhaseCountDownDTO> crossSchemePhaseCountDownList) { private static LightsStatusVO setLightsStatusVOPhaseNoAndCountDown(LightsStatusVO lightsStatusVO, String crossId, int runTime, int planId, List<CrossSchemePhaseCountDownDTO> crossSchemePhaseCountDownList) {
if (!CollectionUtils.isEmpty(crossSchemePhaseCountDownList)) { if (!CollectionUtils.isEmpty(crossSchemePhaseCountDownList)) {
LightsStatusVO lightsStatusVOTemp = new LightsStatusVO();
for (CrossSchemePhaseCountDownDTO dto : crossSchemePhaseCountDownList) { for (CrossSchemePhaseCountDownDTO dto : crossSchemePhaseCountDownList) {
String crossIdCache = dto.getCrossId(); String crossIdCache = dto.getCrossId();
String schemeNoCache = dto.getSchemeNo(); String schemeNoCache = dto.getSchemeNo();
...@@ -208,11 +212,14 @@ public class SignalStatusServiceImpl implements SignalStatusService { ...@@ -208,11 +212,14 @@ public class SignalStatusServiceImpl implements SignalStatusService {
} }
lastPhaseCountTime = changePhaseTime; lastPhaseCountTime = changePhaseTime;
} }
lightsStatusVO.setPhaseId(phaseNo); BeanUtils.copyProperties(lightsStatusVO, lightsStatusVOTemp);
lightsStatusVO.setCyclePhaseCountDown(phaseTimeCountDown); lightsStatusVOTemp.setPhaseId(phaseNo);
lightsStatusVOTemp.setCyclePhaseCountDown(phaseTimeCountDown);
return lightsStatusVOTemp;
} }
} }
} }
return null;
} }
/** /**
......
...@@ -67,7 +67,7 @@ public class XMLUtils { ...@@ -67,7 +67,7 @@ public class XMLUtils {
logOnMessageContent.setMessageContent(body); logOnMessageContent.setMessageContent(body);
logOnMessageContent.setSubSystem("Hisense"); logOnMessageContent.setSubSystem("Hisense");
logOnMessageContent.setFlag(Boolean.TRUE); logOnMessageContent.setFlag("0");
logOnMessageContent.setIsRequest(""); logOnMessageContent.setIsRequest("");
System.err.println(convertToXml(logOnMessageContent)); System.err.println(convertToXml(logOnMessageContent));
...@@ -143,4 +143,12 @@ public class XMLUtils { ...@@ -143,4 +143,12 @@ public class XMLUtils {
} }
return xmlObject; return xmlObject;
} }
public static String strToHex(String str) {
StringBuilder sb = new StringBuilder();
for (char c : str.toCharArray()) {
sb.append(String.format("%02X", (int) c));
}
return sb.toString();
}
} }
...@@ -92,10 +92,11 @@ threadPoolConfig: ...@@ -92,10 +92,11 @@ threadPoolConfig:
queueCapacity: 200 queueCapacity: 200
keepAliveTime: 6000 keepAliveTime: 6000
allowCoreTimeOut: false allowCoreTimeOut: false
#东土通讯端口配置 #海信通讯端口配置
portParam: portParam:
localPort: 55051 localPort: 55051
remotePort: 55050 remotePort: 10010
remoteIp: 172.24.71.68
server: server:
port: 39003 port: 39003
servlet: servlet:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment