作者 钟来

plc终端功能

正在显示 32 个修改的文件 包含 917 行增加338 行删除
... ... @@ -52,7 +52,17 @@ public abstract class ThingsModelItemBase<T> implements ThingsModelBase<T>
BiConsumer<ThingsModelItemBase, String> consumer) {
if (element != null && !element.isJsonNull()) {
String rawValue = element.getAsString();
String rawValue;
if (element.isJsonPrimitive()) {
rawValue = element.getAsString();
} else if (element.isJsonObject() || element.isJsonArray()) {
// 转成字符串,避免 UnsupportedOperationException
rawValue = element.toString();
} else {
rawValue = "0"; // 默认值
}
ThingsModelItemBase item = createThingsModelItemBase(type, model, element);
item.conversionThingsModel(model);
... ... @@ -61,16 +71,17 @@ public abstract class ThingsModelItemBase<T> implements ThingsModelBase<T>
consumer.accept(item, rawValue);
} catch (Exception e) {
log.error("字段 [{}] 处理失败,value={}", model.getModel_name(), rawValue, e);
consumer.accept(item, "0"); // 默认值
consumer.accept(item, "0"); // 出错时兜底
}
} else {
consumer.accept(item, "0");
consumer.accept(item, "0"); // 空字符串兜底
}
return item;
}
return null;
}
private static ThingsModelItemBase createThingsModelItemBase(ThingsModelDataTypeEnum thingsModelDataTypeEnum,IotThingsModel thingsModel,JsonElement jsonElement)
{
String specs = thingsModel.getSpecs();
... ...
... ... @@ -5,6 +5,7 @@ import com.google.gson.JsonObject;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.GsonConstructor;
import com.zhonglai.luhui.action.BaseController;
import com.zhonglai.luhui.api.controller.iot.dto.AddCamera;
import com.zhonglai.luhui.api.controller.iot.dto.HostCommand;
import com.zhonglai.luhui.api.controller.iot.dto.HostCommandFunction;
import com.zhonglai.luhui.api.controller.iot.dto.camera.StartStream;
... ... @@ -189,7 +190,7 @@ public class ControlGkjController extends BaseController {
@ApiImplicitParam(name = "deviceId", value = "设备ID", required = true, dataType = "String", paramType = "path"),
})
@GetMapping("/cameraStartStream/{deviceId}")
public AjaxResult camera(@PathVariable String deviceId, StartStream startStream) {
public AjaxResult camera(@PathVariable String deviceId,@RequestBody StartStream startStream) {
HostCommand hostCommand = new HostCommand();
hostCommand.setFunction("camera");
JSONObject data = new JSONObject();
... ... @@ -208,7 +209,7 @@ public class ControlGkjController extends BaseController {
@ApiImplicitParam(name = "deviceId", value = "设备ID", required = true, dataType = "String", paramType = "path"),
})
@GetMapping("/cameraStartStreamBySerial/{deviceId}")
public AjaxResult cameraStartStreamBySerial(@PathVariable String deviceId, StartStreamBySerial startStreamBySerial) {
public AjaxResult cameraStartStreamBySerial(@PathVariable String deviceId,@RequestBody StartStreamBySerial startStreamBySerial) {
HostCommand hostCommand = new HostCommand();
hostCommand.setFunction("camera");
JSONObject data = new JSONObject();
... ... @@ -227,7 +228,7 @@ public class ControlGkjController extends BaseController {
@ApiImplicitParam(name = "deviceId", value = "设备ID", required = true, dataType = "String", paramType = "path"),
})
@GetMapping("/cameraStopStream/{deviceId}")
public AjaxResult cameraStopStream(@PathVariable String deviceId, StopStream stopStream) {
public AjaxResult cameraStopStream(@PathVariable String deviceId,@RequestBody StopStream stopStream) {
HostCommand hostCommand = new HostCommand();
hostCommand.setFunction("camera");
JSONObject data = new JSONObject();
... ... @@ -240,4 +241,23 @@ public class ControlGkjController extends BaseController {
deviceCommand.setData(GsonConstructor.get().fromJson(GsonConstructor.get().toJson(hostCommand), JsonObject.class));
return rocketMqSendService.deviceControl(deviceCommand);
}
@ApiOperation(value = "添加摄像头")
@ApiImplicitParams({
@ApiImplicitParam(name = "deviceId", value = "设备ID", required = true, dataType = "String", paramType = "path"),
})
@GetMapping("/addCamera/{deviceId}")
public AjaxResult cameraStopStream(@PathVariable String deviceId, @RequestBody AddCamera addCamera) {
HostCommand hostCommand = new HostCommand();
hostCommand.setFunction("camera");
JSONObject data = new JSONObject();
data.put("commd", "addCamera");
data.put("param", GsonConstructor.get().toJson(addCamera));
hostCommand.setData(data);
DeviceCommand deviceCommand = new DeviceCommand();
deviceCommand.setDeviceId(deviceId);
deviceCommand.setCommandType(CommandType.host);
deviceCommand.setData(GsonConstructor.get().fromJson(GsonConstructor.get().toJson(hostCommand), JsonObject.class));
return rocketMqSendService.deviceControl(deviceCommand);
}
}
... ...
package com.zhonglai.luhui.api.controller.iot.dto;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel("添加摄像头对象")
public class AddCamera {
@ApiModelProperty(value = "摄像头序列号",example = "G28890297")
private String id; // "G28890297",
@ApiModelProperty(value = "连接参数",example = "{\"pass\": \"WQMJWP\"}")
private JSONObject connectConfig; // {"pass": "WQMJWP"}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public JSONObject getConnectConfig() {
return connectConfig;
}
public void setConnectConfig(JSONObject connectConfig) {
this.connectConfig = connectConfig;
}
}
... ...
... ... @@ -6,6 +6,8 @@ import com.zhonglai.luhui.device.modbus.terminal.config.InitPlcConfig;
import com.zhonglai.luhui.device.modbus.terminal.data.ParseDataService;
import com.zhonglai.luhui.device.modbus.terminal.modbus.Modbus4jWrite;
import com.zhonglai.luhui.device.modbus.terminal.modbus.ModbusMasterMessage;
import com.zhonglai.luhui.device.modbus.terminal.modbus.dto.PlcSystem;
import com.zhonglai.luhui.device.modbus.terminal.task.CameraDataTask;
import com.zhonglai.luhui.device.modbus.terminal.task.CollectPlcDataTask;
import com.zhonglai.luhui.device.modbus.terminal.task.ScheduledThreadPool;
import com.zhonglai.luhui.device.mqtt.terminal.jar.config.MqttConfig;
... ... @@ -13,6 +15,9 @@ import com.zhonglai.luhui.device.mqtt.terminal.jar.mqtt.MqttService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.List;
import java.util.Map;
public class Main {
private static Log log = LogFactory.getLog(Modbus4jWrite.class);
public static void main(String[] args) throws Exception {
... ... @@ -34,18 +39,21 @@ public class Main {
{
jsonPath = configPath+"/plcs.json";
}
InitPlcConfig.initPlcConfigFromFile(jsonPath);
Map<String, List<PlcSystem>> plcsMap = InitPlcConfig.initPlcConfigFromFile(jsonPath);
String camerapath = Main.class.getClassLoader().getResource("configs/camera.properties").getPath();;
if (null != configPath)
{
camerapath = configPath+"/camera.properties";
}
CameraConfig.init(camerapath);
CameraConfig.init(camerapath,plcsMap.get("cameras"));
CollectPlcDataTask collectPlcDataTask = new CollectPlcDataTask();
collectPlcDataTask.collect(mqttService);
CameraDataTask cameraDataTask = new CameraDataTask();
cameraDataTask.collect(mqttService);
// 添加 JVM 关闭钩子,保证优雅退出
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
log.info("🛑 应用关闭中,正在释放资源...");
... ...
package com.zhonglai.luhui.device.modbus.terminal.camera;
public class Camera {
private String channels;
private String ip;
private String playurls;
private String deviceSerial;
private String pass;
private String rtspurls;
public String getChannels() {
return channels;
}
public void setChannels(String channels) {
this.channels = channels;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getPlayurls() {
return playurls;
}
public void setPlayurls(String playurls) {
this.playurls = playurls;
}
public String getDeviceSerial() {
return deviceSerial;
}
public void setDeviceSerial(String deviceSerial) {
this.deviceSerial = deviceSerial;
}
public String getPass() {
return pass;
}
public void setPass(String pass) {
this.pass = pass;
}
public String getRtspurls() {
return rtspurls;
}
public void setRtspurls(String rtspurls) {
this.rtspurls = rtspurls;
}
}
... ...
package com.zhonglai.luhui.device.modbus.terminal.camera;
public class CameraState {
private static String ip;
private static String playurl;
private static String deviceSerial;
private static String pass;
public static String getIp() {
return ip;
}
public static void setIp(String ip) {
CameraState.ip = ip;
}
public static String getPlayurl() {
return playurl;
}
public static void setPlayurl(String playurl) {
CameraState.playurl = playurl;
}
public static String getDeviceSerial() {
return deviceSerial;
}
public static void setDeviceSerial(String deviceSerial) {
CameraState.deviceSerial = deviceSerial;
}
public static String getPass() {
return pass;
}
public static void setPass(String pass) {
CameraState.pass = pass;
}
}
... ...
... ... @@ -8,15 +8,17 @@ import com.zhonglai.luhui.device.modbus.terminal.config.CameraConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class WebRtcService {
private static Logger logger = LoggerFactory.getLogger(WebRtcService.class);
public static StringBuffer getZlmApi()
{
return new StringBuffer().append("http://").append(CameraConfig.webrtc_host).append("/index/api");
return new StringBuffer().append("http://").append(CameraConfig.webrtcHost).append("/index/api");
}
public static String getPlayUrl(String ip,String app,String stream)
... ... @@ -31,4 +33,16 @@ public class WebRtcService {
return JSON.parseObject(str).containsKey("online") && JSON.parseObject(str).getBoolean("online");
}
public static boolean isWebrtcOnline()
{
InetAddress inet = null;
try {
inet = InetAddress.getByName(CameraConfig.webrtcHost);
boolean ipOk = inet.isReachable(2000); // 2s 超时
return ipOk;
} catch (UnknownHostException e) {
} catch (IOException e) {
}
return false;
}
}
... ...
package com.zhonglai.luhui.device.modbus.terminal.camera.opf;
import com.zhonglai.luhui.device.modbus.terminal.config.CameraConfig;
import com.zhonglai.luhui.device.modbus.terminal.modbus.dto.Message;
import com.zhonglai.luhui.device.modbus.terminal.modbus.dto.PlcSystem;
import java.util.List;
public class AddCamera implements CameraCommdFunction{
private List<PlcSystem> list;
public List<PlcSystem> getList() {
return list;
}
public void setList(List<PlcSystem> list) {
this.list = list;
}
@Override
public Message execute() {
if (list ==null || list.size()==0)
{
return new Message(0,"参数错误");
}
CameraConfig.addCamera( list);
return new Message(1,"添加成功",CameraConfig.cameraList);
}
}
... ...
package com.zhonglai.luhui.device.modbus.terminal.camera.opf;
import com.alibaba.fastjson.JSONObject;
import com.zhonglai.luhui.device.modbus.terminal.modbus.dto.Message;
public interface CameraCommdFunction {
public JSONObject execute();
public Message execute();
}
... ...
package com.zhonglai.luhui.device.modbus.terminal.camera.opf;
import com.alibaba.fastjson.JSONObject;
import com.zhonglai.luhui.device.modbus.terminal.modbus.dto.Message;
/**
* 摄像头操作指令
... ... @@ -41,13 +42,16 @@ public class CameraOperationInstructions {
case "startStreamBySerial":
cameraOperationInstructions.setParam(JSONObject.parseObject(jsonstr, StartStreamBySerial.class));
break;
case "addCamera":
cameraOperationInstructions.setParam(JSONObject.parseObject(jsonstr, AddCamera.class));
break;
case "getLocalIpAddress":
break;
}
return cameraOperationInstructions;
}
public JSONObject execute()
public Message execute()
{
return param.execute();
}
... ...
... ... @@ -3,8 +3,10 @@ package com.zhonglai.luhui.device.modbus.terminal.camera.opf;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zhonglai.luhui.device.modbus.terminal.camera.CameraState;
import com.zhonglai.luhui.device.modbus.terminal.camera.WebRtcService;
import com.zhonglai.luhui.device.modbus.terminal.config.CameraConfig;
import com.zhonglai.luhui.device.modbus.terminal.modbus.dto.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
... ... @@ -39,46 +41,32 @@ public class StartStream implements CameraCommdFunction {
}
@Override
public JSONObject execute() {
public Message execute() {
String[] rtspurls = rtspUrl.split(",");
Message message = new Message();
if(rtspurls.length!=0)
{
String playurls = "";
String localip = CameraConfig.localIp;
for(String rtspurl : rtspurls) {
String newStream = stream;
String playurl = WebRtcService.getPlayUrl(localip, CameraConfig.webrtc_app, newStream);
boolean oline = WebRtcService.isMediaOnline(newStream, CameraConfig.webrtc_app, CameraConfig.webrtcSecret);
String playurl = WebRtcService.getPlayUrl(localip, CameraConfig.webrtcApp, newStream);
boolean oline = WebRtcService.isMediaOnline(newStream, CameraConfig.webrtcApp, CameraConfig.webrtcSecret);
if (!oline)
{
StringBuffer stringBuffer = WebRtcService.getZlmApi();
stringBuffer.append("/addStreamProxy?");
stringBuffer.append("secret=");
stringBuffer.append( CameraConfig.webrtcSecret);
stringBuffer.append("&vhost=__defaultVhost__");
stringBuffer.append("&app=");
stringBuffer.append( CameraConfig.webrtc_app);
stringBuffer.append("&stream=");
stringBuffer.append(newStream);
stringBuffer.append("&url=");
stringBuffer.append(rtspurl);
stringBuffer.append("&enable_auto_close=1");
stringBuffer.append("&retry_count=-1&rtp_type=0&timeout_sec=10&enable_hls=false&enable_hls_fmp4=false&enable_mp4=false&enable_rtsp=true&enable_rtmp=false&enable_ts=false&enable_fmp4=true&hls_demand=false&rtsp_demand=false&rtmp_demand=false&ts_demand=false&fmp4_demand=false&enable_audio=true&add_mute_audio=true&mp4_max_second=10&mp4_as_player=false&auto_close="+auto_close);
logger.info("添加流的接口请求:"+stringBuffer.toString());
String str = HttpUtil.get(stringBuffer.toString());
JSONObject jsonObject = JSON.parseObject(str);
JSONObject jsonObject = httpStreamProxy(rtspurl, newStream, auto_close);
if(jsonObject.containsKey("code") && jsonObject.getInteger("code")==0)
{
jsonObject.put("code",1);
message.setCode(1);
if(!"".equals(playurls))
{
playurls += ",";
}
playurls+=playurl;
}else {
jsonObject.put("code",0);
System.out.println(str);
return jsonObject;
message.setCode(0);
message.setMessage(jsonObject.getString("msg"));
return message;
}
}else{
if(!"".equals(playurls))
... ... @@ -89,17 +77,36 @@ public class StartStream implements CameraCommdFunction {
}
}
JSONObject jsonObject = new JSONObject();
jsonObject.put("code",1);
message.setCode(1);
JSONObject data = new JSONObject();
data.put("playurl",playurls);
data.put("key", CameraConfig.webrtcSecret);
jsonObject.put("data",data);
return jsonObject;
message.setData(data);
return message;
}
message.setCode(0);
message.setMessage("rtspUrl参数错误");
return message;
}
JSONObject jsonObject = new JSONObject();
jsonObject.put("code",0);
jsonObject.put("msg","rtspUrl参数错误");
return jsonObject;
public static JSONObject httpStreamProxy(String rtspurl, String newStream, String auto_close)
{
StringBuffer stringBuffer = WebRtcService.getZlmApi();
stringBuffer.append("/addStreamProxy?");
stringBuffer.append("secret=");
stringBuffer.append( CameraConfig.webrtcSecret);
stringBuffer.append("&vhost=__defaultVhost__");
stringBuffer.append("&app=");
stringBuffer.append( CameraConfig.webrtcApp);
stringBuffer.append("&stream=");
stringBuffer.append(newStream);
stringBuffer.append("&url=");
stringBuffer.append(rtspurl);
stringBuffer.append("&enable_auto_close=1");
stringBuffer.append("&retry_count=-1&rtp_type=0&timeout_sec=10&enable_hls=false&enable_hls_fmp4=false&enable_mp4=false&enable_rtsp=true&enable_rtmp=false&enable_ts=false&enable_fmp4=true&hls_demand=false&rtsp_demand=false&rtmp_demand=false&ts_demand=false&fmp4_demand=false&enable_audio=true&add_mute_audio=true&mp4_max_second=10&mp4_as_player=false&auto_close="+auto_close);
logger.info("添加流的接口请求:"+stringBuffer.toString());
String str = HttpUtil.get(stringBuffer.toString());
return JSON.parseObject(str);
}
}
... ...
... ... @@ -4,6 +4,7 @@ import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zhonglai.luhui.device.modbus.terminal.config.CameraConfig;
import com.zhonglai.luhui.device.modbus.terminal.modbus.dto.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
... ... @@ -29,8 +30,10 @@ public class StartStreamBySerial implements CameraCommdFunction {
}
@Override
public JSONObject execute() {
String str = HttpUtil.get(CameraConfig.yuerleApiUrl+"?deviceSerial="+deviceSerial);
public Message execute() {
String url = CameraConfig.yuerleApiUrl+"?deviceSerial="+deviceSerial;
String str = HttpUtil.get(url);
logger.info("请求接口:{},返回值:{}",url,str);
JSONObject jsonObject = JSON.parseObject(str);
if(jsonObject.containsKey("code") && jsonObject.getInteger("code")==1 && null != jsonObject.get("data"))
{
... ... @@ -42,6 +45,6 @@ public class StartStreamBySerial implements CameraCommdFunction {
startStream.setStream(deviceSerial);
return startStream.execute();
}
return jsonObject;
return new Message(0,jsonObject.getString("msg"));
}
}
... ...
... ... @@ -4,6 +4,7 @@ import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.zhonglai.luhui.device.modbus.terminal.camera.WebRtcService;
import com.zhonglai.luhui.device.modbus.terminal.config.CameraConfig;
import com.zhonglai.luhui.device.modbus.terminal.modbus.dto.Message;
public class StopStream implements CameraCommdFunction {
private String stream;
... ... @@ -17,10 +18,14 @@ public class StopStream implements CameraCommdFunction {
}
@Override
public JSONObject execute() {
String url = WebRtcService.getZlmApi() + "/close_stream?schema=rtsp&vhost=__defaultVhost__&app=" + CameraConfig.webrtc_app + "&stream=" + stream+"&force=1&secret="+ CameraConfig.webrtcSecret;
public Message execute() {
String url = WebRtcService.getZlmApi() + "/close_stream?schema=rtsp&vhost=__defaultVhost__&app=" + CameraConfig.webrtcApp + "&stream=" + stream+"&force=1&secret="+ CameraConfig.webrtcSecret;
String str = HttpUtil.get(url);
System.out.println(str);
return JSONObject.parseObject(str);
JSONObject jsonObject = JSONObject.parseObject(str);
if(jsonObject.getInteger("code") == 200){
return new Message(1, "停止推流成功");
}else {
return new Message(0, jsonObject.getString("msg"));
}
}
}
... ...
package com.zhonglai.luhui.device.modbus.terminal.config;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.net.NetUtil;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zhonglai.luhui.device.modbus.terminal.camera.Camera;
import com.zhonglai.luhui.device.modbus.terminal.camera.WebRtcService;
import com.zhonglai.luhui.device.modbus.terminal.camera.opf.StartStream;
import com.zhonglai.luhui.device.modbus.terminal.modbus.dto.PlcSystem;
import com.zhonglai.luhui.device.mqtt.terminal.jar.config.MqttConfig;
import org.apache.commons.lang3.StringUtils;
import org.ini4j.Ini;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
... ... @@ -11,166 +21,227 @@ import org.slf4j.LoggerFactory;
import java.io.*;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Properties;
public class CameraConfig {
private static Logger logger = LoggerFactory.getLogger(CameraConfig.class);
public static String yuerleApiUrl;
public static String webrtc_host;
private static final Logger logger = LoggerFactory.getLogger(CameraConfig.class);
private static final String CONFIG_PATH = "/app/zlmediakit_config/";
private static final String IP_FILE = CONFIG_PATH + "ip.txt";
private static final String ZLM_CONFIG_FILE = CONFIG_PATH + "config.ini";
private static final Pattern IP_PATTERN = Pattern.compile("rtsp://(?:.*?@)?([0-9.]+)(?::\\d+)?");
private static final Pattern[] CHANNEL_PATTERNS = {
Pattern.compile("/Streaming/Channels/(\\d+)"), // 海康录像盒
Pattern.compile("/ch(\\d+)/"), // 常见摄像头 ch1
Pattern.compile("/channel/(\\d+)"), // 部分厂商 channel/5
Pattern.compile("/live/(\\d+)"), // live/2
Pattern.compile("/sub/(\\d+)"), // sub/1
Pattern.compile("/main/(\\d+)") // main/1
};
public static String yuerleApiUrl;
public static String webrtcHost;
public static String webrtcSecret;
public static String webrtc_app;
public static String webrtcApp;
public static String localIp;
public static void init(String configPath )
{
public static final List<Camera> cameraList = new ArrayList<>();
public static void init(String configPath, List<PlcSystem> list) {
Properties properties = loadProperties(configPath);
yuerleApiUrl = properties.getProperty("yuerleApiUrl");
webrtc_app = properties.getProperty("webrtc_app");
webrtc_host = properties.getProperty("webrtc_host");
webrtcSecret = null==properties.getProperty("webrtcSecret")?getWebrtcSecret():properties.getProperty("webrtcSecret");
String ip = getLocalIp();
localIp = null == ip?getLocalIpAddress():ip;
}
webrtcApp = properties.getProperty("webrtc_app");
webrtcHost = properties.getProperty("webrtc_host");
webrtcSecret = StringUtils.defaultIfBlank(properties.getProperty("webrtcSecret"), getWebrtcSecret());
public static String getLocalIp()
{
File file = new File("/app/zlmediakit_config/ip.txt");
if (file.exists())
localIp = Optional.ofNullable(getLocalIp()).orElseGet(CameraConfig::getLocalIpAddress);
if (WebRtcService.isWebrtcOnline())
{
addCamera(list);
}
}
public static void addCamera(List<PlcSystem> list) {
if (list == null || list.isEmpty()) {
logger.warn("addCamera: 传入的摄像头列表为空");
return;
}
for (PlcSystem plcSystem : list) {
JSONObject connectConfig = plcSystem.getConnectConfig();
if (connectConfig == null) {
logger.warn("设备 {} 缺少 connectConfig,跳过", plcSystem.getId());
continue;
}
Camera camera = new Camera();
camera.setDeviceSerial(plcSystem.getId());
camera.setPass(connectConfig.getString("pass"));
String url = getCameraRtspUrl(camera.getDeviceSerial());
if (StringUtils.isNotBlank(url)) {
camera.setIp(getIpFromUrl(url));
camera.setRtspurls(url);
}
rtspUrl2WebRtc(camera);
cameraList.add(camera);
}
}
private static String getLocalIp() {
File file = new File(IP_FILE);
if (file.exists()) {
String str = FileUtil.readString(file, "utf-8");
String result = str.trim().replaceAll("[\\r\\n]", "");
return result;
return str.trim().replaceAll("[\\r\\n]", "");
}
String localIpEnv = System.getenv("localIp");
if (localIpEnv != null) {
if (StringUtils.isNotBlank(localIpEnv)) {
try {
String realIp = InetAddress.getByName(localIpEnv).getHostAddress();
return realIp;
return InetAddress.getByName(localIpEnv).getHostAddress();
} catch (Exception e) {
logger.error("宿主机 IP 获取失败",e);
logger.error("宿主机 IP 获取失败", e);
}
}
return null;
}
public static String getZLMSecret() {
File file = new File("/app/zlmediakit_config/config.ini");
public static String getLocalIpAddress() {
try (DatagramSocket socket = new DatagramSocket()) {
socket.connect(InetAddress.getByName("8.8.8.8"), 10002);
String ip = socket.getLocalAddress().getHostAddress();
return "0.0.0.0".equals(ip) ? null : ip;
} catch (Exception e) {
logger.error("本机 IP 获取失败", e);
return null;
}
}
if (file.exists())
{
public static String getZLMSecret() {
File file = new File(ZLM_CONFIG_FILE);
if (file.exists()) {
try {
// 读取 config.ini 文件
Ini ini = new Ini(file);
// 获取 [api] 段里的 secret 属性
String secret = ini.get("api", "secret");
logger.info("zlmediakit配置文件读取成功:"+secret);
logger.info("读取 zlmediakit 配置文件成功:{}", secret);
return secret;
} catch (IOException e) {
logger.error("zlmediakit配置文件读取失败",e);
logger.error("读取 zlmediakit 配置文件失败", e);
}
}
String[] command = {
"docker", "exec", "zlmediakit",
"grep", "^secret=", "/opt/media/conf/config.ini"
};
logger.info("正在通过指令{}获取操作令牌...",command);
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.redirectErrorStream(true); // 合并错误流和标准输出流
String[] command = {"docker", "exec", "zlmediakit", "grep", "^secret=", "/opt/media/conf/config.ini"};
logger.info("尝试通过命令行获取操作令牌: {}", Arrays.toString(command));
try {
Process process = processBuilder.start();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()))) {
Process process = new ProcessBuilder(command).redirectErrorStream(true).start();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
logger.info("执行指令返回的数据:{}",line);
if (line.startsWith("secret=")) {
return line.substring("secret=".length()).trim();
}
}
}
int exitCode = process.waitFor();
if (exitCode != 0) {
logger.info("命令执行失败,退出码:"+exitCode);
if (process.waitFor() != 0) {
logger.warn("获取 zlmediakit secret 命令执行失败");
}
} catch (Exception e) {
logger.info("拿操作令牌异常,去配置里面拿:",e);
logger.error("通过命令获取 zlmediakit secret 失败,使用默认值", e);
return "keXTvTDSHAxFDpBA0MDAHhxWeVXLQmUq";
}
return null; // 未找到 secret 或执行失败
return null;
}
/**
* 获取webrtc的密钥
* @return
*/
public static String getWebrtcSecret() {
if(null == webrtcSecret)
{
if (webrtcSecret == null) {
refreshWebrtcSecret();
}
return webrtcSecret;
}
/**
* 刷新webrtc的密钥
*/
public static void refreshWebrtcSecret()
{
public static void refreshWebrtcSecret() {
webrtcSecret = getZLMSecret();
}
private static Properties loadProperties(String path)
{
private static Properties loadProperties(String path) {
Properties properties = new Properties();
try {
if(null != path && !"".equals(path))
{
if (StringUtils.isNotBlank(path)) {
properties.load(new FileReader(path));
}else{
} else {
properties.load(MqttConfig.class.getClassLoader().getResourceAsStream("configs/camera.properties"));
}
} catch (Exception e) {
throw new RuntimeException("加载camera.properties失败,未找到配置文件或内容为空");
throw new RuntimeException("加载 camera.properties 失败", e);
}
return properties;
}
/**
* 获取本机IP
* @return
*/
public static String getLocalIpAddress() {
if(null != localIp)
{
return localIp;
public static String getCameraRtspUrl(String deviceSerial) {
String url = yuerleApiUrl + "?deviceSerial=" + deviceSerial;
String str = HttpUtil.get(url);
logger.info("请求接口:{}, 返回值:{}", url, str);
JSONObject jsonObject = JSON.parseObject(str);
if (jsonObject.getInteger("code") == 1 && jsonObject.containsKey("data")) {
return jsonObject.getString("data");
}
try {
// 构造一个连接外部地址的 socket(这里用 Google 的公共 DNS IP)
try (DatagramSocket socket = new DatagramSocket()) {
socket.connect(InetAddress.getByName("8.8.8.8"), 10002);
InetAddress localAddress = socket.getLocalAddress();
String ip = localAddress.getHostAddress();
if("0.0.0.0".equals(ip))
{
return null;
}
return localIp=ip;
}
} catch (Exception e) {
e.printStackTrace();
public static String rtspUrl2WebRtc(Camera camera) {
if (StringUtils.isBlank(camera.getRtspurls())) {
return null;
}
String[] rtspurls = camera.getRtspurls().split(",");
StringBuilder playUrls = new StringBuilder();
StringBuilder channels = new StringBuilder();
for (String rtspurl : rtspurls) {
String channelNumber = extractChannelId(rtspurl);
String newStream = camera.getDeviceSerial() + "_" + channelNumber;
String playurl = WebRtcService.getPlayUrl(localIp, webrtcApp, newStream);
boolean online = WebRtcService.isMediaOnline(newStream, webrtcApp, webrtcSecret);
if (!online) {
JSONObject jsonObject = StartStream.httpStreamProxy(rtspurl, newStream, "false");
if (!(jsonObject.containsKey("code") && jsonObject.getInteger("code") == 0)) {
continue; // 拉流失败跳过
}
}
if (playUrls.length() > 0) playUrls.append(",");
playUrls.append(playurl);
if (channels.length() > 0) channels.append(",");
channels.append(channelNumber);
}
camera.setPlayurls(playUrls.toString());
camera.setChannels(channels.toString());
return playUrls.toString();
}
public static String getIpFromUrl(String url) {
Matcher ipMatcher = IP_PATTERN.matcher(url);
return ipMatcher.find() ? ipMatcher.group(1) : null;
}
public static String extractChannelId(String url) {
if (url == null) return null;
for (Pattern pattern : CHANNEL_PATTERNS) {
Matcher matcher = pattern.matcher(url);
if (matcher.find()) {
return matcher.group(1);
}
}
return null;
}
}
... ...
... ... @@ -16,14 +16,14 @@ import java.util.Map;
* plc配置
*/
public class InitPlcConfig {
private static Map<Integer, CachPlcConfig> plcsConfigMap = new HashMap<>();
private static Map<String, CachPlcConfig> plcsConfigMap = new HashMap<>();
/**
* 从文件初始化plc点位配置
* @param jsonPath
* @throws IOException
*/
public static void initPlcConfigFromFile(String jsonPath) throws IOException {
public static Map<String, List<PlcSystem>> initPlcConfigFromFile(String jsonPath) throws IOException {
ObjectMapper mapper = new ObjectMapper();
Map<String, List<PlcSystem>> plcsMap = mapper.readValue(new File(jsonPath),
new TypeReference<Map<String, List<PlcSystem>>>() {});
... ... @@ -49,6 +49,7 @@ public class InitPlcConfig {
plc.getPoints().forEach(p -> finalPlcMap.put(p.system, p));
}
}
return plcsMap;
}
/**
... ... @@ -56,7 +57,7 @@ public class InitPlcConfig {
* @param id 系统编号
* @return
*/
public static CachPlcConfig getPlcSystems(Integer id)
public static CachPlcConfig getPlcSystems(String id)
{
return plcsConfigMap.get(id);
}
... ... @@ -67,13 +68,13 @@ public class InitPlcConfig {
* @param id 系统编号
* @return
*/
public static PlcPoint getPlcSystem(Integer id,String system)
public static PlcPoint getPlcSystem(String id,String system)
{
if (plcsConfigMap.containsKey(id) && plcsConfigMap.get(id).getPlcMap().containsKey(system)) return plcsConfigMap.get(id).getPlcMap().get(system);
return null;
}
public static Map<Integer, CachPlcConfig> getPlcsConfigMap()
public static Map<String, CachPlcConfig> getPlcsConfigMap()
{
return plcsConfigMap;
}
... ...
package com.zhonglai.luhui.device.modbus.terminal.data.topic;
import com.zhonglai.luhui.device.modbus.terminal.camera.WebRtcService;
import com.zhonglai.luhui.device.modbus.terminal.camera.opf.CameraOperationInstructions;
import com.zhonglai.luhui.device.modbus.terminal.modbus.dto.Message;
import com.zhonglai.luhui.device.mqtt.terminal.jar.dto.Topic;
import com.zhonglai.luhui.device.mqtt.terminal.jar.mqtt.MqttService;
import com.zhonglai.luhui.device.modbus.terminal.data.TopicFactoryAdapter;
... ... @@ -33,65 +35,63 @@ public class HostTopic extends TopicFactoryAdapter {
String function = jsonObject.getString("function");
JSONObject data = jsonObject.getJSONObject("data");
JSONObject result = new JSONObject();
Message result;
try {
switch (function) {
case "ls":
result.put("result", listFiles());
result = listFiles();
break;
case "cd":
result.put("result", changeDirectory(data.getString("path")));
result = changeDirectory(data.getString("path"));
break;
case "mkdir":
result.put("result", makeDir(data.getString("name")));
result = makeDir(data.getString("name"));
break;
case "rm":
result.put("result", removeFile(data.getString("name")));
result = removeFile(data.getString("name"));
break;
case "copy":
result.put("result", copyFile(data.getString("source"), data.getString("target")));
result = copyFile(data.getString("source"), data.getString("target"));
break;
case "mk":
result.put("result", makeFile(data.getString("name")));
result = makeFile(data.getString("name"));
break;
case "download":
result.put("result", downloadFile(data.getString("url"), data.getString("name")));
result = downloadFile(data.getString("url"), data.getString("name"));
break;
case "upload":
result.put("result", uploadFile(data.getString("name"), data.getString("url")));
result = uploadFile(data.getString("name"), data.getString("url"));
break;
case "camera":
result.put("result", camera(data));
result = camera(data);
break;
default:
result.put("error", "Unknown function: " + function);
result = new Message(0, "Unknown function: " + function);
}
} catch (Exception e) {
result.put("error", e.getMessage());
result = new Message(0, "下位机执行异常", e.getMessage());
}
// 回传执行结果
try {
mqttService.publish("HOST_REQ/"+topicDto.getTime(), result.toJSONString());
String result_str = JSONObject.toJSONString(result);
logger.info("执行结果返回:{}",result_str);
mqttService.publish("HOST_REQ/" + topicDto.getTime(),result_str);
} catch (MqttException e) {
logger.info("返回mqtt指令失败");
}
}
private JSONObject listFiles() throws IOException {
private Message listFiles() throws IOException {
JSONObject result = new JSONObject();
Path dir = currentDir.get();
if (!Files.isDirectory(dir)) {
result.put("error", "Not a directory: " + dir.toString());
return result;
return new Message(0, "Not a directory", dir.toString());
}
// 时间格式化器
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 文件数组
List<JSONObject> files = new ArrayList<>();
Files.list(dir).forEach(path -> {
JSONObject fileObj = new JSONObject();
fileObj.put("name", path.getFileName().toString());
... ... @@ -104,59 +104,66 @@ public class HostTopic extends TopicFactoryAdapter {
fileObj.put("isDirectory", Files.isDirectory(path));
try {
if (Files.isDirectory(path)) {
fileObj.put("size", "-");
} else {
fileObj.put("size", Files.size(path));
}
fileObj.put("size", Files.isDirectory(path) ? "-" : Files.size(path));
} catch (IOException e) {
fileObj.put("size", "unknown");
}
files.add(fileObj);
});
result.put("path", dir.toAbsolutePath().toString());
result.put("files", files);
return result;
return new Message(1, "目录文件列表", result);
}
private String changeDirectory(String path) {
private Message changeDirectory(String path) {
Path newPath = currentDir.get().resolve(path).normalize();
if (Files.isDirectory(newPath)) {
currentDir.set(newPath);
return newPath.toAbsolutePath().toString(); // 返回绝对路径
JSONObject result = new JSONObject();
result.put("path", newPath.toAbsolutePath().toString());
return new Message(1, "切换目录成功", result);
}
return "";
return new Message(0, "目录不存在", path);
}
private String makeDir(String name) throws IOException {
private Message makeDir(String name) throws IOException {
Path newPath = currentDir.get().resolve(name);
Files.createDirectories(newPath);
return newPath.toString();
JSONObject result = new JSONObject();
result.put("path", newPath.toString());
return new Message(1, "目录创建成功",result);
}
private String removeFile(String name) throws IOException {
private Message removeFile(String name) throws IOException {
Path target = currentDir.get().resolve(name);
Files.deleteIfExists(target);
return target.toString();
boolean deleted = Files.deleteIfExists(target);
JSONObject result = new JSONObject();
result.put("path", target.toString());
return deleted
? new Message(1, "删除成功", result)
: new Message(0, "文件不存在", result);
}
private String copyFile(String source, String target) throws IOException {
private Message copyFile(String source, String target) throws IOException {
Path src = currentDir.get().resolve(source);
Path tgt = currentDir.get().resolve(target);
Files.copy(src, tgt, StandardCopyOption.REPLACE_EXISTING);
return "Copied from " + src.toString() + " to " + tgt.toString();
JSONObject result = new JSONObject();
result.put("from", src.toString());
result.put("to", tgt.toString());
return new Message(1, "文件复制成功", result);
}
private String makeFile(String name) throws IOException {
private Message makeFile(String name) throws IOException {
Path file = currentDir.get().resolve(name);
Files.createFile(file);
return "File created: " + file.toString();
JSONObject result = new JSONObject();
result.put("path", file.toString());
return new Message(1, "文件创建成功", result);
}
private String downloadFile(String urlStr, String fileName) throws IOException {
private Message downloadFile(String urlStr, String fileName) throws IOException {
Path target = currentDir.get().resolve(fileName);
URL url = new URL(urlStr);
... ... @@ -172,13 +179,15 @@ public class HostTopic extends TopicFactoryAdapter {
out.write(buffer, 0, len);
}
}
return "Downloaded file to " + target.toString();
JSONObject result = new JSONObject();
result.put("path", target.toString());
return new Message(1, "下载成功", result);
}
private String uploadFile(String fileName, String urlStr) throws IOException {
private Message uploadFile(String fileName, String urlStr) throws IOException {
Path file = currentDir.get().resolve(fileName);
if (!Files.exists(file)) {
return "File not found: " + file.toString();
return new Message(0, "文件不存在", file.toString());
}
String boundary = "----WebKitFormBoundary" + System.currentTimeMillis();
... ... @@ -196,7 +205,6 @@ public class HostTopic extends TopicFactoryAdapter {
PrintWriter writer = new PrintWriter(new OutputStreamWriter(out, "UTF-8"), true);
FileInputStream inputStream = new FileInputStream(file.toFile())) {
// --- 表单文件头
writer.append("--").append(boundary).append(LINE_FEED);
writer.append("Content-Disposition: form-data; name=\"file\"; filename=\"")
.append(file.getFileName().toString()).append("\"").append(LINE_FEED);
... ... @@ -204,7 +212,6 @@ public class HostTopic extends TopicFactoryAdapter {
writer.append(LINE_FEED);
writer.flush();
// --- 文件内容
byte[] buffer = new byte[8192];
int len;
while ((len = inputStream.read(buffer)) != -1) {
... ... @@ -212,7 +219,6 @@ public class HostTopic extends TopicFactoryAdapter {
}
out.flush();
// --- 文件结束
writer.append(LINE_FEED).flush();
writer.append("--").append(boundary).append("--").append(LINE_FEED);
writer.flush();
... ... @@ -220,11 +226,11 @@ public class HostTopic extends TopicFactoryAdapter {
int responseCode = conn.getResponseCode();
String responseMsg = "";
InputStream respStream = null;
InputStream respStream;
try {
respStream = conn.getInputStream();
} catch (IOException e) {
respStream = conn.getErrorStream(); // 出错时取 errorStream
respStream = conn.getErrorStream();
}
if (respStream != null) {
StringBuilder sb = new StringBuilder();
... ... @@ -236,17 +242,22 @@ public class HostTopic extends TopicFactoryAdapter {
responseMsg = sb.toString().trim();
reader.close();
}
return "Uploaded " + file.toString() + " to " + urlStr +
" (HTTP " + responseCode + ") response: " + responseMsg;
JSONObject result = new JSONObject();
result.put("HTTP", responseCode);
result.put("response", responseMsg);
return new Message(1, "上传成功", result);
}
private String camera(JSONObject parameter) throws IOException {
CameraOperationInstructions cameraOperationInstructions = CameraOperationInstructions.createCameraOperationInstructions( parameter);
if (null != cameraOperationInstructions)
private Message camera(JSONObject parameter) throws IOException {
if (!WebRtcService.isWebrtcOnline())
{
return cameraOperationInstructions.execute().toJSONString();
return new Message(0, "ZLM未启动");
}
CameraOperationInstructions cameraOperationInstructions =
CameraOperationInstructions.createCameraOperationInstructions(parameter);
if (null != cameraOperationInstructions) {
return cameraOperationInstructions.execute();
}
return "camera ok" ;
return new Message(0, "不支持的操作");
}
}
... ...
... ... @@ -28,7 +28,7 @@ public class PutTopic extends TopicFactoryAdapter {
for (String key : jsonObject.keySet())
{
JSONObject plcCommand = jsonObject.getJSONObject(key);
Integer id = Integer.parseInt(key);
String id = key;
List<PlcPoint> plcPoints = getPlcPoints(id, plcCommand);
try {
new Modbus4jWrite(id).batchWrite(plcPoints,true);
... ... @@ -45,7 +45,7 @@ public class PutTopic extends TopicFactoryAdapter {
}
}
private List<PlcPoint> getPlcPoints(Integer id,JSONObject plcCommand)
private List<PlcPoint> getPlcPoints(String id,JSONObject plcCommand)
{
List<PlcPoint> plcPoints = new ArrayList<>();
for (String pointName : plcCommand.keySet())
... ...
... ... @@ -31,7 +31,7 @@ public class ReadTopic extends TopicFactoryAdapter {
for (String key : jsonObject.keySet())
{
String plcCommand = jsonObject.getString(key);
Integer id = Integer.parseInt(key);
String id = key;
List<PlcPoint> plcPoints = getPlcPoints(id, plcCommand);
try {
Map<String, Object> map = new Modbus4jRead(id).batchRead(plcPoints,true);
... ... @@ -48,7 +48,7 @@ public class ReadTopic extends TopicFactoryAdapter {
}
}
private List<PlcPoint> getPlcPoints(Integer id,String plcCommand)
private List<PlcPoint> getPlcPoints(String id,String plcCommand)
{
List<PlcPoint> plcPoints = new ArrayList<>();
for (String pointName : plcCommand.split(","))
... ...
... ... @@ -26,7 +26,7 @@ public class Modbus4jRead {
private ModbusMaster master;
public Modbus4jRead(Integer id) throws Exception {
public Modbus4jRead(String id) throws Exception {
this.master = ModbusMasterMessage.createMaster(id);
}
... ...
... ... @@ -33,7 +33,7 @@ public class Modbus4jWrite {
static Log log = LogFactory.getLog(Modbus4jWrite.class);
private ModbusMaster master;
public Modbus4jWrite(Integer id) throws Exception {
public Modbus4jWrite(String id) throws Exception {
this.master = ModbusMasterMessage.createMaster(id);
}
... ...
... ... @@ -26,16 +26,16 @@ public class ModbusMasterMessage {
}
// 存储每个系统的 ModbusMaster
private static final ConcurrentHashMap<Integer, ModbusMaster> masterCache = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<String, ModbusMaster> masterCache = new ConcurrentHashMap<>();
// 每个系统 ID 对应的锁对象
private static final ConcurrentHashMap<Integer, Object> lockMap = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<String, Object> lockMap = new ConcurrentHashMap<>();
/**
* 创建或获取 ModbusMaster (线程安全)
*/
public static ModbusMaster createMaster(Integer id) throws Exception {
public static ModbusMaster createMaster(String id) throws Exception {
ModbusMaster master = masterCache.get(id);
if (master != null && master.isConnected()) {
return master;
... ... @@ -67,7 +67,7 @@ public class ModbusMasterMessage {
}
private static ModbusMaster selectMaster(Integer id) throws Exception {
private static ModbusMaster selectMaster(String id) throws Exception {
CachPlcConfig cachPlcConfig = InitPlcConfig.getPlcSystems(id);
if (null == cachPlcConfig)
... ... @@ -94,7 +94,7 @@ public class ModbusMasterMessage {
/**
* 关闭指定系统的 Master
*/
public static void closeMaster(Integer id) {
public static void closeMaster(String id) {
Object lock = lockMap.computeIfAbsent(id, k -> new Object());
synchronized (lock) {
ModbusMaster master = masterCache.remove(id);
... ...
... ... @@ -6,7 +6,7 @@ import com.fasterxml.jackson.databind.util.JSONPObject;
import java.util.Map;
public class CachPlcConfig {
private Integer id;
private String id;
private String systemName;
private ProtocolType protocolType;
private JSONObject connectConfig;
... ... @@ -44,11 +44,11 @@ public class CachPlcConfig {
this.protocolType = protocolType;
}
public Integer getId() {
public String getId() {
return id;
}
public void setId(Integer id) {
public void setId(String id) {
this.id = id;
}
}
... ...
package com.zhonglai.luhui.device.modbus.terminal.modbus.dto;
public class Message {
private int code;
private String message;
private Object data;
public Message() {
}
public Message(int code, String message) {
this.code = code;
this.message = message;
}
public Message(int code, String message, Object data) {
this.code = code;
this.message = message;
this.data = data;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
... ...
... ... @@ -4,7 +4,7 @@ import com.alibaba.fastjson.JSONObject;
import java.util.List;
public class PlcSystem {
private Integer id;
private String id;
private String systemName;
private ProtocolType protocolType;
private JSONObject connectConfig;
... ... @@ -42,11 +42,11 @@ public class PlcSystem {
this.points = points;
}
public Integer getId() {
public String getId() {
return id;
}
public void setId(Integer id) {
public void setId(String id) {
this.id = id;
}
}
\ No newline at end of file
... ...
package com.zhonglai.luhui.device.modbus.terminal.task;
import com.alibaba.fastjson.JSONObject;
import com.zhonglai.luhui.device.modbus.terminal.camera.Camera;
import com.zhonglai.luhui.device.modbus.terminal.camera.WebRtcService;
import com.zhonglai.luhui.device.modbus.terminal.config.CameraConfig;
import com.zhonglai.luhui.device.modbus.terminal.config.InitPlcConfig;
import com.zhonglai.luhui.device.modbus.terminal.modbus.dto.CachPlcConfig;
import com.zhonglai.luhui.device.modbus.terminal.modbus.dto.PlcPoint;
import com.zhonglai.luhui.device.mqtt.terminal.jar.mqtt.MqttService;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 定时上报摄像头数据
*/
public class CameraDataTask {
protected static final Logger logger = LoggerFactory.getLogger(CameraDataTask.class);
public void collect(MqttService mqttService) {
ScheduledThreadPool.scheduler.scheduleAtFixedRate(() -> {
try {
if (WebRtcService.isWebrtcOnline())
{
pubMqttData(mqttService);
}
}catch (Exception e)
{
logger.info("plc通讯异常:{}",e.getMessage());
}
},0, 60, TimeUnit.SECONDS);
}
private void pubMqttData(MqttService mqttService)
{
JSONObject jsonObject = new JSONObject();
CameraConfig.cameraList.forEach(camera -> {
if(!checkCameraConnectivity(camera)) //如果摄像头的ip不正常,重新获取摄像头ip
{
String rtspUrl = CameraConfig.getCameraRtspUrl(camera.getDeviceSerial());
if (StringUtils.isNotBlank(rtspUrl)) {
camera.setIp(CameraConfig.getIpFromUrl(rtspUrl));
camera.setRtspurls(rtspUrl);
}
CameraConfig.rtspUrl2WebRtc(camera);
}
jsonObject.put("4_"+camera.getDeviceSerial(),camera);
});
if(!jsonObject.isEmpty())
{
try {
mqttService.publish("ADD_POST",jsonObject.toJSONString());
} catch (MqttException e) {
logger.error("mqtt连接异常",e);
}
}
}
/**
* 提交主机数据
*/
public static void putHostDate(MqttService mqttService)
{
try {
JSONObject jsonObject = new JSONObject();
JSONObject data = new JSONObject();
data.put("localhost",CameraConfig.localIp);
jsonObject.put("0",data);
mqttService.publish("ADD_POST",jsonObject.toJSONString());
} catch (MqttException e) {
logger.error("mqtt连接异常",e);
}
}
/**
* 检测单个摄像头的 IP 和 RTSP 连通性
* @param camera 摄像头对象
* @return true = 可达,false = 不可达
*/
public static boolean checkCameraConnectivity(Camera camera) {
if (camera == null) {
return false;
}
boolean ipOk = false;
boolean rtspOk = false;
// 检查 IP 连通性
String ip = camera.getIp();
if (StringUtils.isNotBlank(ip)) {
try {
InetAddress inet = InetAddress.getByName(ip);
ipOk = inet.isReachable(2000); // 2s 超时
} catch (Exception e) {
logger.error("设备 {} IP {} 不可达", camera.getDeviceSerial(), ip, e);
}
}
if (!ipOk)
{
return false;
}
// 检查 RTSP 端口连通性
String rtspUrls = camera.getRtspurls();
if (StringUtils.isNotBlank(rtspUrls)) {
String[] urls = rtspUrls.split(",");
for (String url : urls) {
try {
URI uri = new URI(url);
String host = uri.getHost();
int port = (uri.getPort() == -1) ? 554 : uri.getPort(); // 默认 RTSP 端口 554
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(host, port), 2000);
rtspOk = true;
break; // 只要有一个成功,就认为 RTSP 可用
}
} catch (Exception e) {
logger.warn("设备 {} RTSP 地址 {} 无法连接", camera.getDeviceSerial(), url);
}
}
}
boolean finalResult = ipOk && rtspOk;
logger.info("检测结果 => 设备 {}: IP={}, RTSP={}, 总结果={}",
camera.getDeviceSerial(), ipOk, rtspOk, finalResult);
return finalResult;
}
}
... ...
... ... @@ -39,8 +39,8 @@ public class CollectPlcDataTask {
private void pubMqttData(MqttService mqttService)
{
//查看可以访问的plc
Map<Integer, CachPlcConfig> plcConfigMap = InitPlcConfig.getPlcsConfigMap();
for (Integer plcId : plcConfigMap.keySet())
Map<String, CachPlcConfig> plcConfigMap = InitPlcConfig.getPlcsConfigMap();
for (String plcId : plcConfigMap.keySet())
{
CachPlcConfig cachPlcConfig = plcConfigMap.get(plcId);
try {
... ... @@ -51,7 +51,7 @@ public class CollectPlcDataTask {
}
}
private void pubMqttData(MqttService mqttService, Integer plcId,CachPlcConfig cachPlcConfig) throws Exception
private void pubMqttData(MqttService mqttService, String plcId,CachPlcConfig cachPlcConfig) throws Exception
{
Map<String, PlcPoint> map = cachPlcConfig.getPlcMap();
... ... @@ -89,7 +89,7 @@ public class CollectPlcDataTask {
}
}
private boolean subMqttData(MqttService mqttService, Integer plcId, List<PlcPoint> plcPoints)
private boolean subMqttData(MqttService mqttService, String plcId, List<PlcPoint> plcPoints)
{
//通知
try {
... ...
{
"cameras": [
{
"id": "G28890297",
"connectConfig": {"pass": "WQMJWP"}
}
],
"plcs": [
{
"id": 6,
"id": "2_6",
"systemName": "测试",
"protocolType": "TCP",
"connectConfig": { "host": "192.168.1.82", "port": 2000},
... ... @@ -14,30 +20,30 @@
{"name": "氧锥泵4故障", "system": "yzb4gz", "address": "40001.06", "dataType": "bit","access":"r"},
{"name": "排污泵故障", "system": "pwb_gz", "address": "40001.07", "dataType": "bit","access":"r"},
{"name": "排污阀1开不到位", "system": "pwf1kbdw", "address": "40001.09", "dataType": "bit","access":"r"},
{"name": "溶氧上限报警设定值", "system": "ry_sxsz", "address": "40053-40054", "dataType": "float32","order": "CDAB","access":"rw"},
{"name": "溶氧下限报警设定值", "system": "ry_xxsz", "address": "40055-40056", "dataType": "float32","order": "CDAB","access":"rw"}
{"name": "溶氧上限报警设定值", "system": "ry_sxsz", "address": "40053-40054", "dataType": "float32","order": "ABCD","access":"rw"},
{"name": "溶氧下限报警设定值", "system": "ry_xxsz", "address": "40055-40056", "dataType": "float32","order": "ABCD","access":"rw"}
]
},
{
"id": 1,
"id": "2_1",
"systemName": "成鱼系统1",
"protocolType": "TCP",
"connectConfig": { "host": "192.168.1.19", "port": 2000},
"connectConfig": { "host": "192.168.2.11", "port": 2000},
"points": [
{"name": "自动", "system": "zd", "address": "10001", "dataType": "bit"},
{"name": "远程", "system": "yc", "address": "10002", "dataType": "bit"},
{"name": "补水泵启动", "system": "bsbqd", "address": "10003", "dataType": "bit"},
{"name": "水泵1运行", "system": "sb1yx", "address": "10004", "dataType": "bit"},
{"name": "水泵2运行", "system": "sb2yx", "address": "10005", "dataType": "bit"},
{"name": "水泵1运行", "system": "sb1", "address": "10004", "dataType": "bit"},
{"name": "水泵2运行", "system": "sb2", "address": "10005", "dataType": "bit"},
{"name": "氧锥泵1运行", "system": "yzb1yx", "address": "10006", "dataType": "bit"},
{"name": "氧锥泵2运行", "system": "yzb2yx", "address": "10007", "dataType": "bit"},
{"name": "氧锥泵3运行", "system": "yzb3yx", "address": "10008", "dataType": "bit"},
{"name": "氧锥泵4运行", "system": "yzb4yx", "address": "10009", "dataType": "bit"},
{"name": "排污泵运行", "system": "pwb", "address": "10010", "dataType": "bit"},
{"name": "微滤机电源合闸", "system": "wljdyhz", "address": "10011", "dataType": "bit"},
{"name": "微滤机电源合闸", "system": "wlj", "address": "10011", "dataType": "bit"},
{"name": "紫外灯电源合闸", "system": "zwd", "address": "10012", "dataType": "bit"},
{"name": "微滤池液位高", "system": "wlcyw_g", "address": "10013", "dataType": "bit"},
{"name": "微滤池液位低", "system": "wlcyw_d", "address": "10014", "dataType": "bit"},
{"name": "微滤池高液位", "system": "wlq", "address": "10013", "dataType": "bit"},
{"name": "微滤池低液位", "system": "wld", "address": "10014", "dataType": "bit"},
{"name": "蝶阀1开到位", "system": "df1kdw", "address": "10015", "dataType": "bit"},
{"name": "蝶阀1关到位", "system": "df1gdw", "address": "10016", "dataType": "bit"},
{"name": "蝶阀2开到位", "system": "df2kdw", "address": "10017", "dataType": "bit"},
... ... @@ -81,19 +87,19 @@
{"name": "排污阀8关不到位", "system": "pwf8gbdw", "address": "40002.08", "dataType": "bit"},
{"name": "补水高液位超时", "system": "bsgywdcs", "address": "40002.11", "dataType": "bit"},
{"name": "微滤池高液位超时", "system": "wlcgywdcs", "address": "40002.12", "dataType": "bit"},
{"name": "微滤机电源跳闸", "system": "wljdytz", "address": "40002.13", "dataType": "bit"},
{"name": "紫外杀菌灯跳闸", "system": "zwsjd_tz", "address": "40002.14", "dataType": "bit"},
{"name": "微滤机跳闸", "system": "wljtz", "address": "40002.13", "dataType": "bit"},
{"name": "紫外杀菌灯跳闸故障", "system": "zwsjdtz","address": "40002.14", "dataType": "bit"},
{"name": "溶氧超限报警", "system": "rycxbj", "address": "40002.15", "dataType": "bit"},
{"name": "微滤池低液位长时间不消失报警", "system": "wlcdywbcsbj", "address": "40002.16", "dataType": "bit"},
{"name": "溶氧值", "system": "ry", "address": "40003-40004", "dataType": "float32"},
{"name": "温度值", "system": "wd", "address": "40005-40006", "dataType": "float32"},
{"name": "电能值", "system": "dn", "address": "40007-40008", "dataType": "float32"},
{"name": "溶氧值", "system": "ryz", "address": "40003-40004","order": "ABCD", "dataType": "float32"},
{"name": "温度值", "system": "wdz", "address": "40005-40006","order": "ABCD", "dataType": "float32"},
{"name": "电能值", "system": "dnz", "address": "40007-40008","order": "ABCD", "dataType": "float32"},
{"name": "当前氧锥泵运行台数", "system": "dqyzb", "address": "40009", "dataType": "int16"},
{"name": "氧锥泵1运行时间", "system": "yzb1_sj", "address": "40011-40012", "dataType": "int32"},
{"name": "氧锥泵2运行时间", "system": "yzb2_sj", "address": "40013-40014", "dataType": "int32"},
{"name": "氧锥泵3运行时间", "system": "yzb3_sj", "address": "40015-40016", "dataType": "int32"},
{"name": "氧锥泵4运行时间", "system": "yzb4_sj", "address": "40017-40018", "dataType": "int32"},
{"name": "生化池水温", "system": "shcsw", "address": "40019-40020", "dataType": "float32"},
{"name": "氧锥泵1运行时间", "system": "yzb1_sj", "address": "40011-40012","order": "ABCD", "dataType": "int32"},
{"name": "氧锥泵2运行时间", "system": "yzb2_sj", "address": "40013-40014","order": "ABCD", "dataType": "int32"},
{"name": "氧锥泵3运行时间", "system": "yzb3_sj", "address": "40015-40016","order": "ABCD", "dataType": "int32"},
{"name": "氧锥泵4运行时间", "system": "yzb4_sj", "address": "40017-40018","order": "ABCD", "dataType": "int32"},
{"name": "生化池水温", "system": "shcsw", "address": "40019-40020","order": "ABCD", "dataType": "float32"},
{"name": "循环水泵故障", "system": "xhsb_gz", "address": "40021.01", "dataType": "bit"},
{"name": "生化池水温低限报警", "system": "shcsw_dx_bj", "address": "40021.02", "dataType": "bit"},
{"name": "生化池水温高限报警", "system": "shcsw_gx_bj", "address": "40021.03", "dataType": "bit"},
... ... @@ -105,28 +111,28 @@
{"name": "排污阀6开OR关", "system": "pwf6_or", "address": "40051.06", "dataType": "bit"},
{"name": "排污阀7开OR关", "system": "pwf7_or", "address": "40051.07", "dataType": "bit"},
{"name": "排污阀8开OR关", "system": "pwf8_or", "address": "40051.08", "dataType": "bit"},
{"name": "水泵1启动", "system": "sb1_qd", "address": "40051.09", "dataType": "bit"},
{"name": "水泵2启动", "system": "sb2_qd", "address": "40051.10", "dataType": "bit"},
{"name": "水泵1启动", "system": "sb1start", "address": "40051.09", "dataType": "bit"},
{"name": "水泵2启动", "system": "sb2start", "address": "40051.10", "dataType": "bit"},
{"name": "氧锥泵1启动", "system": "yzb1_qd", "address": "40051.11", "dataType": "bit"},
{"name": "氧锥泵2启动", "system": "yzb2_qd", "address": "40051.12", "dataType": "bit"},
{"name": "氧锥泵3启动", "system": "yzb3_qd", "address": "40051.13", "dataType": "bit"},
{"name": "氧锥泵4启动", "system": "yzb4_qd", "address": "40051.14", "dataType": "bit"},
{"name": "排污泵启动", "system": "pwb_qd", "address": "40051.15", "dataType": "bit"},
{"name": "水泵1停止", "system": "sb1_tz", "address": "40052.01", "dataType": "bit"},
{"name": "水泵2停止", "system": "sb2_tz", "address": "40052.02", "dataType": "bit"},
{"name": "水泵1停止", "system": "sb1stop", "address": "40052.01", "dataType": "bit"},
{"name": "水泵2停止", "system": "sb2stop", "address": "40052.02", "dataType": "bit"},
{"name": "氧锥泵1停止", "system": "yzb1_tz", "address": "40052.03", "dataType": "bit"},
{"name": "氧锥泵2停止", "system": "yzb2_tz", "address": "40052.04", "dataType": "bit"},
{"name": "氧锥泵3停止", "system": "yzb3_tz", "address": "40052.05", "dataType": "bit"},
{"name": "氧锥泵4停止", "system": "yzb4_tz", "address": "40052.06", "dataType": "bit"},
{"name": "排污泵停止", "system": "pwb_tz", "address": "40052.07", "dataType": "bit"},
{"name": "清报警", "system": "qbj", "address": "40052.09", "dataType": "bit"},
{"name": "累计时间清零", "system": "lj_sjql", "address": "40052.10", "dataType": "bit"},
{"name": "溶氧上限报警设定值", "system": "ry_sxsz", "address": "40053-40054", "dataType": "float32"},
{"name": "溶氧下限报警设定值", "system": "ry_xxsz", "address": "40055-40056", "dataType": "float32"}
{"name": "累计时间清零", "system": "ljtq", "address": "40052.10", "dataType": "bit"},
{"name": "溶氧上限报警设定值", "system": "rysjup", "address": "40053-40054","order": "ABCD", "dataType": "float32"},
{"name": "溶氧下限报警设定值", "system": "rysjdown", "address": "40055-40056","order": "ABCD", "dataType": "float32"}
]
},
{
"id": 2,
"id": "2_2",
"systemName": "成鱼系统2",
"protocolType": "TCP",
"connectConfig": { "host": "192.168.2.2", "port": 2001},
... ... @@ -134,17 +140,17 @@
{"name": "自动", "system": "zd", "address": "10001", "dataType": "bit"},
{"name": "远程", "system": "yc", "address": "10002", "dataType": "bit"},
{"name": "补水泵启动", "system": "bsbqd", "address": "10003", "dataType": "bit"},
{"name": "水泵1运行", "system": "sb1yx", "address": "10004", "dataType": "bit"},
{"name": "水泵2运行", "system": "sb2yx", "address": "10005", "dataType": "bit"},
{"name": "水泵1运行", "system": "sb1", "address": "10004", "dataType": "bit"},
{"name": "水泵2运行", "system": "sb2", "address": "10005", "dataType": "bit"},
{"name": "氧锥泵1运行", "system": "yzb1yx", "address": "10006", "dataType": "bit"},
{"name": "氧锥泵2运行", "system": "yzb2yx", "address": "10007", "dataType": "bit"},
{"name": "氧锥泵3运行", "system": "yzb3yx", "address": "10008", "dataType": "bit"},
{"name": "氧锥泵4运行", "system": "yzb4yx", "address": "10009", "dataType": "bit"},
{"name": "排污泵运行", "system": "pwb", "address": "10010", "dataType": "bit"},
{"name": "微滤机电源合闸", "system": "wljdyhz", "address": "10011", "dataType": "bit"},
{"name": "微滤机电源合闸", "system": "wlj", "address": "10011", "dataType": "bit"},
{"name": "紫外灯电源合闸", "system": "zwd", "address": "10012", "dataType": "bit"},
{"name": "微滤池液位高", "system": "wlcyw_g", "address": "10013", "dataType": "bit"},
{"name": "微滤池液位低", "system": "wlcyw_d", "address": "10014", "dataType": "bit"},
{"name": "微滤池高液位", "system": "wlq", "address": "10013", "dataType": "bit"},
{"name": "微滤池低液位", "system": "wld", "address": "10014", "dataType": "bit"},
{"name": "蝶阀1开到位", "system": "df1kdw", "address": "10015", "dataType": "bit"},
{"name": "蝶阀1关到位", "system": "df1gdw", "address": "10016", "dataType": "bit"},
{"name": "蝶阀2开到位", "system": "df2kdw", "address": "10017", "dataType": "bit"},
... ... @@ -188,19 +194,19 @@
{"name": "排污阀8关不到位", "system": "pwf8gbdw", "address": "40002.08", "dataType": "bit"},
{"name": "补水高液位超时", "system": "bsgywdcs", "address": "40002.11", "dataType": "bit"},
{"name": "微滤池高液位超时", "system": "wlcgywdcs", "address": "40002.12", "dataType": "bit"},
{"name": "微滤机电源跳闸", "system": "wljdytz", "address": "40002.13", "dataType": "bit"},
{"name": "紫外杀菌灯跳闸", "system": "zwsjd_tz", "address": "40002.14", "dataType": "bit"},
{"name": "微滤机跳闸", "system": "wljtz", "address": "40002.13", "dataType": "bit"},
{"name": "紫外杀菌灯跳闸故障", "system": "zwsjdtz", "address": "40002.14", "dataType": "bit"},
{"name": "溶氧超限报警", "system": "rycxbj", "address": "40002.15", "dataType": "bit"},
{"name": "微滤池低液位长时间不消失报警", "system": "wlcdywbcsbj", "address": "40002.16", "dataType": "bit"},
{"name": "溶氧值", "system": "ry", "address": "40003-40004", "dataType": "float32"},
{"name": "温度值", "system": "wd", "address": "40005-40006", "dataType": "float32"},
{"name": "电能值", "system": "dn", "address": "40007-40008", "dataType": "float32"},
{"name": "微滤池低液位长时间不消失报警", "system": "wldc", "address": "40002.16", "dataType": "bit"},
{"name": "溶氧值", "system": "ryz", "address": "40003-40004","order": "ABCD", "dataType": "float32"},
{"name": "温度值", "system": "wdz", "address": "40005-40006","order": "ABCD", "dataType": "float32"},
{"name": "电能值", "system": "dnz", "address": "40007-40008","order": "ABCD", "dataType": "float32"},
{"name": "当前氧锥泵运行台数", "system": "dqyzb", "address": "40009", "dataType": "int16"},
{"name": "氧锥泵1运行时间", "system": "yzb1_sj", "address": "40011-40012", "dataType": "int32"},
{"name": "氧锥泵2运行时间", "system": "yzb2_sj", "address": "40013-40014", "dataType": "int32"},
{"name": "氧锥泵3运行时间", "system": "yzb3_sj", "address": "40015-40016", "dataType": "int32"},
{"name": "氧锥泵4运行时间", "system": "yzb4_sj", "address": "40017-40018", "dataType": "int32"},
{"name": "生化池水温", "system": "shcsw", "address": "40019-40020", "dataType": "float32"},
{"name": "氧锥泵1运行时间", "system": "yzb1_sj", "address": "40011-40012","order": "ABCD", "dataType": "int32"},
{"name": "氧锥泵2运行时间", "system": "yzb2_sj", "address": "40013-40014","order": "ABCD", "dataType": "int32"},
{"name": "氧锥泵3运行时间", "system": "yzb3_sj", "address": "40015-40016","order": "ABCD", "dataType": "int32"},
{"name": "氧锥泵4运行时间", "system": "yzb4_sj", "address": "40017-40018","order": "ABCD", "dataType": "int32"},
{"name": "生化池水温", "system": "shcsw", "address": "40019-40020","order": "ABCD", "dataType": "float32"},
{"name": "循环水泵故障", "system": "xhsb_gz", "address": "40021.01", "dataType": "bit"},
{"name": "生化池水温低限报警", "system": "shcsw_dx_bj", "address": "40021.02", "dataType": "bit"},
{"name": "生化池水温高限报警", "system": "shcsw_gx_bj", "address": "40021.03", "dataType": "bit"},
... ... @@ -212,28 +218,28 @@
{"name": "排污阀6开OR关", "system": "pwf6_or", "address": "40051.06", "dataType": "bit"},
{"name": "排污阀7开OR关", "system": "pwf7_or", "address": "40051.07", "dataType": "bit"},
{"name": "排污阀8开OR关", "system": "pwf8_or", "address": "40051.08", "dataType": "bit"},
{"name": "水泵1启动", "system": "sb1_qd", "address": "40051.09", "dataType": "bit"},
{"name": "水泵2启动", "system": "sb2_qd", "address": "40051.10", "dataType": "bit"},
{"name": "水泵1启动", "system": "sb1start", "address": "40051.09", "dataType": "bit"},
{"name": "水泵2启动", "system": "sb2start", "address": "40051.10", "dataType": "bit"},
{"name": "氧锥泵1启动", "system": "yzb1_qd", "address": "40051.11", "dataType": "bit"},
{"name": "氧锥泵2启动", "system": "yzb2_qd", "address": "40051.12", "dataType": "bit"},
{"name": "氧锥泵3启动", "system": "yzb3_qd", "address": "40051.13", "dataType": "bit"},
{"name": "氧锥泵4启动", "system": "yzb4_qd", "address": "40051.14", "dataType": "bit"},
{"name": "排污泵启动", "system": "pwb_qd", "address": "40051.15", "dataType": "bit"},
{"name": "水泵1停止", "system": "sb1_tz", "address": "40052.01", "dataType": "bit"},
{"name": "水泵2停止", "system": "sb2_tz", "address": "40052.02", "dataType": "bit"},
{"name": "水泵1停止", "system": "sb1stop", "address": "40052.01", "dataType": "bit"},
{"name": "水泵2停止", "system": "sb2stop", "address": "40052.02", "dataType": "bit"},
{"name": "氧锥泵1停止", "system": "yzb1_tz", "address": "40052.03", "dataType": "bit"},
{"name": "氧锥泵2停止", "system": "yzb2_tz", "address": "40052.04", "dataType": "bit"},
{"name": "氧锥泵3停止", "system": "yzb3_tz", "address": "40052.05", "dataType": "bit"},
{"name": "氧锥泵4停止", "system": "yzb4_tz", "address": "40052.06", "dataType": "bit"},
{"name": "排污泵停止", "system": "pwb_tz", "address": "40052.07", "dataType": "bit"},
{"name": "清报警", "system": "qbj", "address": "40052.09", "dataType": "bit"},
{"name": "累计时间清零", "system": "lj_sjql", "address": "40052.10", "dataType": "bit"},
{"name": "溶氧上限报警设定值", "system": "ry_sxsz", "address": "40053-40054", "dataType": "float32"},
{"name": "溶氧下限报警设定值", "system": "ry_xxsz", "address": "40055-40056", "dataType": "float32"}
{"name": "累计时间清零", "system": "ljtq", "address": "40052.10", "dataType": "bit"},
{"name": "溶氧上限报警设定值", "system": "rysjup", "address": "40053-40054","order": "ABCD", "dataType": "float32"},
{"name": "溶氧下限报警设定值", "system": "rysjdown", "address": "40055-40056","order": "ABCD", "dataType": "float32"}
]
},
{
"id": 3,
"id": "2_3",
"systemName": "源水处理区",
"protocolType": "TCP",
"connectConfig": { "host": "192.168.2.5", "port": 2004},
... ... @@ -245,25 +251,27 @@
{"name": "水源泵3启动", "system": "syp3", "address": "10005", "dataType": "bit"},
{"name": "风机1启动", "system": "fj1", "address": "10006", "dataType": "bit"},
{"name": "风机2启动", "system": "fj2", "address": "10007", "dataType": "bit"},
{"name": "紫外灯电源合闸", "system": "zw", "address": "10008", "dataType": "bit"},
{"name": "紫外灯电源合闸", "system": "zwd", "address": "10008", "dataType": "bit"},
{"name": "生化池高液位", "system": "shg", "address": "10009", "dataType": "bit"},
{"name": "生化池低液位", "system": "shd", "address": "10010", "dataType": "bit"},
{"name": "系统报警", "system": "xtbj", "address": "00001", "dataType": "bit"},
{"name": "水源泵1故障", "system": "syp1g", "address": "40001.01", "dataType": "bit"},
{"name": "水源泵2故障", "system": "syp2g", "address": "40001.02", "dataType": "bit"},
{"name": "水源泵3故障", "system": "syp3g", "address": "40001.03", "dataType": "bit"},
{"name": "风机1故障", "system": "fj1g", "address": "40001.04", "dataType": "bit"},
{"name": "风机2故障", "system": "fj2g", "address": "40001.05", "dataType": "bit"},
{"name": "紫外杀菌等跳闸故障", "system": "zwg", "address": "40001.06", "dataType": "bit"},
{"name": "电能值", "system": "dn", "address": "40007-40008", "dataType": "float"},
{"name": "紫外杀菌灯跳闸故障", "system": "zwsjdtz", "address": "40001.06", "dataType": "bit"},
{"name": "电能值", "system": "dnz", "address": "40007-40008","order": "ABCD", "dataType": "float"},
{"name": "当前水源泵启动台数", "system": "dqsy", "address": "40009", "dataType": "int"},
{"name": "当前风机运行台数", "system": "dqfj", "address": "40010", "dataType": "int"},
{"name": "水源泵1启动时间", "system": "syp1sj", "address": "40011-40012", "dataType": "long"},
{"name": "水源泵2启动时间", "system": "syp2sj", "address": "40013-40014", "dataType": "long"},
{"name": "水源泵3启动时间", "system": "syp3sj", "address": "40015-40016", "dataType": "long"},
{"name": "风机1启动时间", "system": "fj1sj", "address": "40017-40018", "dataType": "long"},
{"name": "风机2启动时间", "system": "fj2sj", "address": "40019-40020", "dataType": "long"},
{"name": "补水阀1开OR关", "system": "bsf1", "address": "40051.01", "dataType": "bit"},
{"name": "补水阀2开OR关", "system": "bsf2", "address": "40051.02", "dataType": "bit"},
{"name": "水源泵1运行时间", "system": "syp1sj", "address": "40011-40012","order": "ABCD", "dataType": "long"},
{"name": "水源泵2运行时间", "system": "syp2sj", "address": "40013-40014","order": "ABCD", "dataType": "long"},
{"name": "水源泵3运行时间", "system": "syp3sj", "address": "40015-40016","order": "ABCD", "dataType": "long"},
{"name": "风机1运行时间", "system": "fj1t", "address": "40017-40018","order": "ABCD", "dataType": "long"},
{"name": "风机2运行时间", "system": "fj2t", "address": "40019-40020","order": "ABCD", "dataType": "long"},
{"name": "水源泵1启动", "system": "syp1s", "address": "40051.01", "dataType": "bit"},
{"name": "水源泵2启动", "system": "syp2s", "address": "40051.02", "dataType": "bit"},
{"name": "水源泵3启动", "system": "syp3s", "address": "40051.03", "dataType": "bit"},
... ... @@ -272,14 +280,14 @@
{"name": "水源泵1停止", "system": "syp1t", "address": "40051.09", "dataType": "bit"},
{"name": "水源泵2停止", "system": "syp2t", "address": "40051.10", "dataType": "bit"},
{"name": "水源泵3停止", "system": "syp3t", "address": "40051.11", "dataType": "bit"},
{"name": "风机1停止", "system": "fj1t", "address": "40051.12", "dataType": "bit"},
{"name": "风机2停止", "system": "fj2t", "address": "40051.13", "dataType": "bit"},
{"name": "风机1停止", "system": "fj1p", "address": "40051.12", "dataType": "bit"},
{"name": "风机2停止", "system": "fj2p", "address": "40051.13", "dataType": "bit"},
{"name": "清报警", "system": "qbj", "address": "40052.01", "dataType": "bit"},
{"name": "累计时间清零", "system": "ljsj", "address": "40052.02", "dataType": "bit"}
{"name": "累计时间清零", "system": "ljtq", "address": "40052.02", "dataType": "bit"}
]
},
{
"id": 4,
"id": "2_4",
"systemName": "育苗系统",
"protocolType": "TCP",
"connectConfig": { "host": "192.168.2.4", "port": 2002},
... ... @@ -296,38 +304,51 @@
{"name": "紫外灯电源合闸", "system": "zwd", "address": "10011", "dataType": "bit"},
{"name": "补水池高液位", "system": "bsc", "address": "10012", "dataType": "bit"},
{"name": "微滤池高液位", "system": "wlq", "address": "10013", "dataType": "bit"},
{"name": "溶氧超限报警", "system": "rycj", "address": "10015", "dataType": "bit"},
{"name": "微滤池低液位", "system": "wld", "address": "10015", "dataType": "bit"},
{"name": "微滤池低液位长时间不消失报警", "system": "wldc", "address": "10016", "dataType": "bit"},
{"name": "系统报警", "system": "xtbj", "address": "00001", "dataType": "bit"},
{"name": "溶氧值", "system": "ryz", "address": "40003-40004", "dataType": "float32"},
{"name": "温度值", "system": "wdz", "address": "40005-40006", "dataType": "float32"},
{"name": "电能值", "system": "dnz", "address": "40007-40008", "dataType": "float32"},
{"name": "水泵1故障", "system": "sb1gz", "address": "40001.02", "dataType": "bit"},
{"name": "水泵2故障", "system": "sb2gz", "address": "40001.03", "dataType": "bit"},
{"name": "风机1故障", "system": "fj1g", "address": "40001.04", "dataType": "bit"},
{"name": "风机2故障", "system": "fj2g", "address": "40001.05", "dataType": "bit"},
{"name": "热泵1跳闸", "system": "rb1tz", "address": "40001.08", "dataType": "bit"},
{"name": "热泵2跳闸", "system": "rb2tz", "address": "40001.09", "dataType": "bit"},
{"name": "微滤机跳闸", "system": "wljtz", "address": "40001.10", "dataType": "bit"},
{"name": "紫外杀菌灯跳闸故障", "system": "zwsjdtz", "address": "40001.11", "dataType": "bit"},
{"name": "补水上液位超时", "system": "bssywcs", "address": "40001.12", "dataType": "bit"},
{"name": "微滤池上液位超时", "system": "wlcsywcs", "address": "40001.13", "dataType": "bit"},
{"name": "溶氧超限报警", "system": "rycxbj", "address": "40001.14", "dataType": "bit"},
{"name": "补水泵3故障(没有)", "system": "bsb3g", "address": "40001.15", "dataType": "bit"},
{"name": "微滤池低液位长时间不消失报警", "system": "wldc", "address": "40001.16", "dataType": "bit"},
{"name": "溶氧值", "system": "ryz", "address": "40003-40004","order": "ABCD", "dataType": "float32"},
{"name": "温度值", "system": "wdz", "address": "40005-40006","order": "ABCD", "dataType": "float32"},
{"name": "电能值", "system": "dnz", "address": "40007-40008","order": "ABCD", "dataType": "float32"},
{"name": "当前风机运行台数", "system": "dqfj", "address": "40009", "dataType": "int32"},
{"name": "风机1运行时间", "system": "fj1sj", "address": "40011-40012", "dataType": "int64"},
{"name": "风机2运行时间", "system": "fj2sj", "address": "40013-40014", "dataType": "int64"},
{"name": "风机1运行时间", "system": "fj1t", "address": "40011-40012","order": "ABCD", "dataType": "long"},
{"name": "风机2运行时间", "system": "fj2t", "address": "40013-40014","order": "ABCD", "dataType": "long"},
{"name": "水泵1启动", "system": "sb1start", "address": "40051.01", "dataType": "bit"},
{"name": "水泵2启动", "system": "sb2start", "address": "40051.02", "dataType": "bit"},
{"name": "风机1启动", "system": "fj1start", "address": "40051.03", "dataType": "bit"},
{"name": "风机2启动", "system": "fj2start", "address": "40051.04", "dataType": "bit"},
{"name": "补水泵3启动", "system": "bsp3start", "address": "40051.05", "dataType": "bit"},
{"name": "风机1启动", "system": "fj1s", "address": "40051.03", "dataType": "bit"},
{"name": "风机2启动", "system": "fj2s", "address": "40051.04", "dataType": "bit"},
{"name": "补水泵3启动", "system": "bsb3s", "address": "40051.05", "dataType": "bit"},
{"name": "水泵1停止", "system": "sb1stop", "address": "40051.09", "dataType": "bit"},
{"name": "水泵2停止", "system": "sb2stop", "address": "40051.10", "dataType": "bit"},
{"name": "风机1停止", "system": "fj1stop", "address": "40051.11", "dataType": "bit"},
{"name": "风机2停止", "system": "fj2stop", "address": "40051.12", "dataType": "bit"},
{"name": "补水泵3停止", "system": "bsp3stop", "address": "40051.13", "dataType": "bit"},
{"name": "风机1停止", "system": "fj1p", "address": "40051.11", "dataType": "bit"},
{"name": "风机2停止", "system": "fj2p", "address": "40051.12", "dataType": "bit"},
{"name": "补水泵3停止", "system": "bsb3p", "address": "40051.13", "dataType": "bit"},
{"name": "清报警", "system": "qbj", "address": "40052.01", "dataType": "bit"},
{"name": "累计时间清零", "system": "ljsjql", "address": "40052.02", "dataType": "bit"},
{"name": "累计时间清零", "system": "ljtq", "address": "40052.02", "dataType": "bit"},
{"name": "溶氧上限报警设定值", "system": "rysjup", "address": "40053-40054", "dataType": "float32"},
{"name": "溶氧下限报警设定值", "system": "rysjdown", "address": "40055-40056", "dataType": "float32"}
{"name": "溶氧上限报警设定值", "system": "rysjup", "address": "40053-40054","order": "ABCD", "dataType": "float32"},
{"name": "溶氧下限报警设定值", "system": "rysjdown", "address": "40055-40056","order": "ABCD", "dataType": "float32"}
]
},
{
"id": 5,
"id": "2_5",
"systemName": "设备房系统",
"protocolType": "TCP",
"connectConfig": { "host": "192.168.2.3", "port": 2003},
... ... @@ -349,7 +370,7 @@
{"name": "补水阀2关到位", "system": "bsf2g", "address": "10017", "dataType": "bit"},
{"name": "补水1高液位", "system": "bsg1", "address": "10019", "dataType": "bit"},
{"name": "补水2高液位", "system": "bsg2", "address": "10020", "dataType": "bit"},
{"name": "系统报警", "system": "bj", "address": "00001", "dataType": "bit"},
{"name": "系统报警", "system": "xtbj", "address": "00001", "dataType": "bit"},
{"name": "风机1故障", "system": "fj1g", "address": "40001.01", "dataType": "bit"},
{"name": "风机2故障", "system": "fj2g", "address": "40001.02", "dataType": "bit"},
... ... @@ -365,12 +386,12 @@
{"name": "补水阀2关不到位", "system": "bsf2bg", "address": "40001.13", "dataType": "bit"},
{"name": "空压机跳闸故障", "system": "kyjg", "address": "40001.16", "dataType": "bit"},
{"name": "电能值", "system": "dnz", "address": "40007-40008", "dataType": "float"},
{"name": "电能值", "system": "dnz", "address": "40007-40008","order": "ABCD", "dataType": "float"},
{"name": "当前风机运行台数", "system": "dqfj", "address": "40009", "dataType": "int"},
{"name": "风机1运行时间", "system": "fj1t", "address": "40011-40012", "dataType": "long"},
{"name": "风机2运行时间", "system": "fj2t", "address": "40013-40014", "dataType": "long"},
{"name": "风机3运行时间", "system": "fj3t", "address": "40015-40016", "dataType": "long"},
{"name": "风机4运行时间", "system": "fj4t", "address": "40017-40018", "dataType": "long"},
{"name": "风机1运行时间", "system": "fj1t", "address": "40011-40012","order": "ABCD", "dataType": "long"},
{"name": "风机2运行时间", "system": "fj2t", "address": "40013-40014","order": "ABCD", "dataType": "long"},
{"name": "风机3运行时间", "system": "fj3t", "address": "40015-40016","order": "ABCD", "dataType": "long"},
{"name": "风机4运行时间", "system": "fj4t", "address": "40017-40018","order": "ABCD", "dataType": "long"},
{"name": "补水阀1开OR关", "system": "bsf1c", "address": "40051.01", "dataType": "bit"},
{"name": "补水阀2开OR关", "system": "bsf2c", "address": "40051.02", "dataType": "bit"},
... ...
... ... @@ -24,7 +24,7 @@ public class TestModbus {
private static void testRead(String[] args) throws Exception {
String jsonPath = args[0];
boolean zeroBasedAddress = new Boolean(args[1]);
Integer id = Integer.parseInt(args[2]);
String id = args[2];
List<String> pointNames = Arrays.asList(Arrays.copyOfRange(args, 3, args.length));
InitPlcConfig.initPlcConfigFromFile(jsonPath);
... ... @@ -46,7 +46,7 @@ public class TestModbus {
{
String jsonPath = args[0];
boolean zeroBasedAddress = new Boolean(args[1]);
Integer id = Integer.parseInt(args[2]);
String id = args[2];
List<String> pointNames = Arrays.asList(Arrays.copyOfRange(args, 3, args.length));
InitPlcConfig.initPlcConfigFromFile(jsonPath);
... ...
... ... @@ -35,6 +35,8 @@ public class DefaultProtocolParserFactoryImpl implements ProtocolParserFactory {
return new PutReq().analysisPayload(payload);
case "READ_REQ":
return new ReadReq().analysisPayload(payload);
case "HOST_REQ":
return new HostReq().analysisPayload(payload);
default:
return new AnalysisResult(false,false,null);
}
... ...
package com.zhonglai.luhui.device.protocol.defaul.analysis.topic;
import com.google.gson.JsonObject;
import com.ruoyi.common.utils.GsonConstructor;
import com.zhonglai.luhui.device.analysis.comm.dto.ApiClientRePlyDto;
import com.zhonglai.luhui.device.analysis.dto.MessageCode;
import com.zhonglai.luhui.device.protocol.factory.dto.AnalysisResult;
import java.util.HashMap;
public class HostReq {
public AnalysisResult analysisPayload(byte[] payload)
{
return analysisPayload(new String(payload));
}
public AnalysisResult analysisPayload(String payload) {
JsonObject jsonObject = GsonConstructor.get().fromJson(payload, JsonObject.class);
ApiClientRePlyDto message = new ApiClientRePlyDto();
if(jsonObject.has("code") && "1".equals(jsonObject.get("code").getAsString()))
{
if (jsonObject.has("data"))
{
message.setData(GsonConstructor.get().fromJson(jsonObject.getAsJsonObject("data"), HashMap.class));
}
message.setCode(MessageCode.DEFAULT_SUCCESS_CODE);
message.setMessage("操作成功");
}
return new AnalysisResult(false, true, null, message);
}
}
... ...
... ... @@ -154,12 +154,7 @@ public class DeviceCommandListenService implements RocketMQReplyListener<Message
{
return new Message(MessageCode.DEFAULT_FAIL_CODE,"该设备不支持主机操作功能");
}
if(clienNoticeServiceFactory.sendMessage(noticeMessageDomain))
{
return new Message(MessageCode.DEFAULT_SUCCESS_CODE,"指令发送成功");
}else {
return new Message(MessageCode.DEFAULT_FAIL_CODE,"指令发送失败");
}
return sendMessage(noticeMessageDomain);
default:
return new Message(MessageCode.DEFAULT_FAIL_CODE,"指令类型不存在,请联系管理员");
}
... ... @@ -225,7 +220,7 @@ public class DeviceCommandListenService implements RocketMQReplyListener<Message
clienConnection.reply(apiClientRePlyDto);
}
}
log.info("结束通知{}",clientid);
log.info("结束通知{},数据:{}",clientid,GsonConstructor.get().toJson(apiClientRePlyDto));
}
@Override
... ...
... ... @@ -241,30 +241,52 @@ public class IotThingsModelService {
* @param vjsonObject
* @return
*/
private JSONObject reverseTranslateModeData(Integer product_id, JSONObject vjsonObject )
{
for(String vkey:vjsonObject.keySet())
{
if(GsonConstructor.get().fromJson(vjsonObject.get(vkey).toString(),JsonElement.class).isJsonObject())
{
private JSONObject reverseTranslateModeData(Integer product_id, JSONObject vjsonObject) {
for (String vkey : vjsonObject.keySet()) {
Object rawValue = vjsonObject.get(vkey);
// 用 Gson 统一转成 JsonElement,避免多次 toString()/parse
JsonElement jsonElement = GsonConstructor.get().fromJson(String.valueOf(rawValue), JsonElement.class);
if (jsonElement != null && jsonElement.isJsonObject()) {
JSONObject jsData = vjsonObject.getJSONObject(vkey);
for(String key:jsData.keySet())
{
IotThingsModel thingsModel = getThingsModelBase(product_id,key);
for (String key : jsData.keySet()) {
IotThingsModel thingsModel = getThingsModelBase(product_id, key);
String data_type = thingsModel.getData_type().toUpperCase();
if(!EnumUtils.isValidEnum(ThingsModelDataTypeEnum.class,data_type))
{
if (!EnumUtils.isValidEnum(ThingsModelDataTypeEnum.class, data_type)) {
data_type = ThingsModelDataTypeEnum.STRING.name();
}
ThingsModelItemBase thingsModelBase = ThingsModelItemBase.newhingsModelReverse(Enum.valueOf(ThingsModelDataTypeEnum.class,data_type),thingsModel, GsonConstructor.get().fromJson(jsData.get(key).toString(), JsonElement.class));
jsData.put(key,thingsModelBase.getValue());
// 不要再无脑 toString(),直接走 safeNewhingsModel
JsonElement fieldElement = GsonConstructor.get().fromJson(
String.valueOf(jsData.get(key)),
JsonElement.class
);
ThingsModelItemBase thingsModelBase =
ThingsModelItemBase.newhingsModelReverse(
Enum.valueOf(ThingsModelDataTypeEnum.class, data_type),
thingsModel,
fieldElement
);
// 如果 thingsModelBase 不为空就覆盖,否则给默认值
if (thingsModelBase != null && thingsModelBase.getValue() != null) {
jsData.put(key, thingsModelBase.getValue());
} else {
jsData.put(key, "0"); // 默认值兜底
}
}
vjsonObject.put(vkey,jsData);
vjsonObject.put(vkey, jsData);
}
}
return vjsonObject;
}
private IotThingsModel getThingsModelBase(Integer product_id,String identifier)
{
IotThingsModel thingsModel = getIotThingsModel(product_id,identifier);
... ...