作者 钟来

plc终端功能

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