作者 钟来

模块整理

正在显示 53 个修改的文件 包含 2697 行增加44 行删除
@@ -15,7 +15,7 @@ public class SysParameter { @@ -15,7 +15,7 @@ public class SysParameter {
15 15
16 public static String service_ip = ""; //服务所在地址 16 public static String service_ip = ""; //服务所在地址
17 17
18 - @Value("${mqtt.topicconfig:/{{roleid}}/{{username}}/{{clientid}}/{{topicType}}/{{messageid}}}") 18 + @Value("${mqtt.topicconfig:/{{roleid}}/{{username}}/{{topicType}}/{{clientid}}}")
19 public String tempTopicconfig ; //topic 配置 19 public String tempTopicconfig ; //topic 配置
20 20
21 @Value("${mqtt.topics") 21 @Value("${mqtt.topics")
@@ -21,9 +21,11 @@ public class DBFactoryImp implements DBFactory{ @@ -21,9 +21,11 @@ public class DBFactoryImp implements DBFactory{
21 try { 21 try {
22 if(null==ds ) 22 if(null==ds )
23 { 23 {
24 - String path = System.getProperty("user.dir")+"/configs/"; 24 + String dbPath = System.getProperty("dbPath");
  25 + String path = null != dbPath?dbPath:System.getProperty("user.dir")+"/configs/";
25 Properties p = new Properties(); 26 Properties p = new Properties();
26 - p.load(new FileInputStream(new File(path+"dbcpconfig.properties"))); 27 + System.out.println("》》》》》》》》》》》》》数据库配置文件地址:"+path+"dbcpconfig.properties");
  28 + p.load(new FileInputStream(path+"dbcpconfig.properties"));
27 // p.load(DBFactory.class 29 // p.load(DBFactory.class
28 // .getClassLoader().getResourceAsStream("configs/dbcpconfig.properties")); 30 // .getClassLoader().getResourceAsStream("configs/dbcpconfig.properties"));
29 ds = BasicDataSourceFactory.createDataSource(p); 31 ds = BasicDataSourceFactory.createDataSource(p);
@@ -188,4 +188,12 @@ public class ByteUtil { @@ -188,4 +188,12 @@ public class ByteUtil {
188 crc = crc.substring(2, 4) + crc.substring(0, 2); 188 crc = crc.substring(2, 4) + crc.substring(0, 2);
189 return crc.toUpperCase(); 189 return crc.toUpperCase();
190 } 190 }
  191 +
  192 + public static String changerTwoStr(String str) {
  193 + if (null == str && "".equals(str)) {
  194 + return "00";
  195 + } else {
  196 + return str.length() == 1 ? "0" + str : str.substring(str.length() - 2, str.length());
  197 + }
  198 + }
191 } 199 }
@@ -6,8 +6,8 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; @@ -6,8 +6,8 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
6 import org.springframework.context.annotation.ComponentScan; 6 import org.springframework.context.annotation.ComponentScan;
7 7
8 @ComponentScan(basePackages = { 8 @ComponentScan(basePackages = {
9 - "com.zhonglai.luhui.config",  
10 - "com.zhonglai.luhui.controller", 9 + "com.zhonglai.luhui.lsy.plc.service.config",
  10 + "com.zhonglai.luhui.lsy.plc.service.controller",
11 } 11 }
12 ) 12 )
13 @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) 13 @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
1 package com.zhonglai.luhui.data.file.service.baidu; 1 package com.zhonglai.luhui.data.file.service.baidu;
2 2
  3 +import cn.hutool.core.bean.BeanUtil;
  4 +import cn.hutool.core.io.FileUtil;
  5 +import cn.hutool.db.Db;
  6 +import cn.hutool.db.Entity;
  7 +import cn.hutool.http.HttpRequest;
  8 +import cn.hutool.http.HttpResponse;
  9 +import cn.hutool.http.HttpUtil;
  10 +import com.google.gson.JsonArray;
  11 +import com.google.gson.JsonObject;
  12 +import com.ruoyi.common.core.domain.Message;
  13 +import com.ruoyi.common.core.domain.MessageCode;
  14 +import com.ruoyi.common.utils.DateUtils;
  15 +import com.ruoyi.common.utils.GsonConstructor;
3 import com.zhonglai.luhui.data.file.service.config.SysConfig; 16 import com.zhonglai.luhui.data.file.service.config.SysConfig;
  17 +import com.zhonglai.luhui.data.file.service.dto.BaiduFileInfo;
  18 +import com.zhonglai.luhui.data.file.service.dto.SysTripartitePlatformToken;
4 19
5 -import java.io.BufferedReader;  
6 -import java.io.InputStreamReader;  
7 -import java.net.HttpURLConnection;  
8 -import java.net.URL; 20 +import java.io.*;
  21 +import java.net.*;
  22 +import java.sql.SQLException;
  23 +import java.util.ArrayList;
  24 +import java.util.HashMap;
  25 +import java.util.List;
  26 +import java.util.Map;
9 27
10 /** 28 /**
11 * 百度网盘服务 29 * 百度网盘服务
12 */ 30 */
13 public class BaiDuWangPanService { 31 public class BaiDuWangPanService {
  32 + public static String typestr = "BaiDuWangPanToken_ZL";
  33 +
14 /** 34 /**
15 * 获取授权地址 35 * 获取授权地址
16 * @param redirect_uri 36 * @param redirect_uri
@@ -76,6 +96,140 @@ public class BaiDuWangPanService { @@ -76,6 +96,140 @@ public class BaiDuWangPanService {
76 return null; 96 return null;
77 } 97 }
78 98
  99 + public static String getToken()
  100 + {
  101 + try {
  102 + Entity entity = Db.use().get("sys_tripartite_platform_token","tripartite_platform_type",typestr);
  103 + if(null == entity)
  104 + {
  105 + return null;
  106 + }
  107 + SysTripartitePlatformToken sysTripartitePlatformToken = entity.toBean(SysTripartitePlatformToken.class);
  108 + int time = DateUtils.getNowTimeMilly();
  109 + if((sysTripartitePlatformToken.getAccess_token_end_time()-time)<=3600)
  110 + {
  111 + if((sysTripartitePlatformToken.getRefresh_token_end_time()-time)<=(24*60*60))
  112 + {
  113 + String str = BaiDuWangPanService.refreshToken(sysTripartitePlatformToken.getRefresh_token());
  114 + BaiDuWangPanResponse baiDuWangPanResponse = GsonConstructor.get().fromJson(str,BaiDuWangPanResponse.class);
  115 + sysTripartitePlatformToken.setAccess_token(baiDuWangPanResponse.getAccess_token());
  116 + sysTripartitePlatformToken.setAccess_token_end_time(sysTripartitePlatformToken.getUpdate_time()+baiDuWangPanResponse.getExpires_in());
  117 + sysTripartitePlatformToken.setRefresh_token(baiDuWangPanResponse.getRefresh_token());
  118 + sysTripartitePlatformToken.setRefresh_token_end_time(sysTripartitePlatformToken.getUpdate_time()+(10*365*24*60*60));
  119 + sysTripartitePlatformToken.setUpdate_time(DateUtils.getNowTimeMilly());
  120 + Db.use().update(Entity.create().parse(sysTripartitePlatformToken).setTableName("sys_tripartite_platform_token"),Entity.create().addFieldNames("id"));
  121 + return sysTripartitePlatformToken.getAccess_token();
  122 + }
  123 + return null;
  124 + }
  125 + return sysTripartitePlatformToken.getAccess_token();
  126 + } catch (SQLException e) {
  127 + throw new RuntimeException(e);
  128 + }
  129 +
  130 +
  131 + }
  132 +
  133 + /**
  134 + * 文件列表
  135 + * @param path
  136 + * @param token
  137 + * @param pageNum
  138 + * @param pageSize
  139 + * @return
  140 + */
  141 + public static List<BaiduFileInfo> getFileList(String path,String token,Integer pageNum,Integer pageSize)
  142 + {
  143 + String str = HttpUtil.get("https://pan.baidu.com/rest/2.0/xpan/file?method=list&dir="+path+"&order=time&start="+((pageNum-1)*pageSize)+"&limit="+pageSize+"&web=web&folder=0&access_token="+token+"&desc=1");
  144 + System.out.println(str);
  145 + JsonObject jsonObject = GsonConstructor.get().fromJson(str, JsonObject.class);
  146 +
  147 + JsonArray jsonArray = jsonObject.get("list").getAsJsonArray();
  148 + List<BaiduFileInfo> list = new ArrayList<>();
  149 + for (int i=0;i<jsonArray.size();i++)
  150 + {
  151 + JsonObject file = jsonArray.get(i).getAsJsonObject();
  152 + BaiduFileInfo baiduFileInfo = GsonConstructor.get().fromJson(file.toString(),BaiduFileInfo.class);
  153 + list.add(baiduFileInfo);
  154 + }
  155 + return list;
  156 + }
  157 +
  158 + /**
  159 + * 递归获取文件列表
  160 + * @param path
  161 + * @param token
  162 + * @param pageNum
  163 + * @param pageSize
  164 + * @return
  165 + */
  166 + public static List<BaiduFileInfo> getRecursionFileList(String path,String token,Integer pageNum,Integer pageSize)
  167 + {
  168 + String str = HttpUtil.get("http://pan.baidu.com/rest/2.0/xpan/multimedia?method=listall&path="+path+"&access_token="+token+"&web=1&recursion=1&start="+((pageNum-1)*pageSize)+"&limit="+pageSize);
  169 + System.out.println(str);
  170 + JsonObject jsonObject = GsonConstructor.get().fromJson(str, JsonObject.class);
  171 +
  172 + List<BaiduFileInfo> list = new ArrayList<>();
  173 + if (jsonObject.has("list") && null != jsonObject.get("list"))
  174 + {
  175 + JsonArray jsonArray = jsonObject.get("list").getAsJsonArray();
  176 +
  177 + for (int i=0;i<jsonArray.size();i++)
  178 + {
  179 + JsonObject file = jsonArray.get(i).getAsJsonObject();
  180 + BaiduFileInfo baiduFileInfo = GsonConstructor.get().fromJson(file.toString(),BaiduFileInfo.class);
  181 + list.add(baiduFileInfo);
  182 + }
  183 + }
  184 +
  185 + return list;
  186 + }
  187 +
  188 + /**
  189 + * 搜索文件
  190 + * @param path
  191 + * @param token
  192 + * @return
  193 + */
  194 + public static List<BaiduFileInfo> findFileList(String path,String token,String key,Integer pageNum)
  195 + {
  196 + String str = HttpUtil.get("http://pan.baidu.com/rest/2.0/xpan/file?dir=/apps/test&access_token="+token+"&web=1&recursion=1&page="+pageNum+"&num=2&method=search&key="+key+"&dir="+path);
  197 + JsonArray jsonArray = GsonConstructor.get().fromJson(str,JsonObject.class).get("list").getAsJsonArray();
  198 +
  199 + List<BaiduFileInfo> list = new ArrayList<>();
  200 + for (int i=0;i<jsonArray.size();i++)
  201 + {
  202 + JsonObject jsonObject = jsonArray.get(i).getAsJsonObject();
  203 + BaiduFileInfo baiduFileInfo = GsonConstructor.get().fromJson(jsonObject.toString(),BaiduFileInfo.class);
  204 + list.add(baiduFileInfo);
  205 + }
  206 + return list;
  207 + }
  208 +
  209 + /**
  210 + * 上传文件
  211 + * @param token
  212 + * @return
  213 + */
  214 + public static int upLoadFile( File file,String savepath,String token)
  215 + {
  216 + HttpRequest request = HttpUtil.createPost("https://d.pcs.baidu.com/rest/2.0/pcs/file?method=upload&access_token="+token+"&path="+savepath);
  217 + request.form("file", file); // 上传文件
  218 + // 发送请求
  219 + HttpResponse response = request.execute();
79 220
  221 + if(response.isOk()) {
  222 + System.out.println("上传成功!");
  223 + return 1;
  224 + } else {
  225 + JsonObject jsonObject = GsonConstructor.get().fromJson(response.body(),JsonObject.class);
  226 + if(jsonObject.has("error_code") && jsonObject.get("error_code").getAsInt()==31061)
  227 + {
  228 + return 2;
  229 + }
  230 + System.out.println("上传失败!"+response.body());
  231 + }
  232 + return 0;
  233 + }
80 234
81 } 235 }
@@ -29,7 +29,6 @@ import java.sql.SQLException; @@ -29,7 +29,6 @@ import java.sql.SQLException;
29 @RequestMapping("/baiDuWangPan") 29 @RequestMapping("/baiDuWangPan")
30 public class BaiDuWangPanController { 30 public class BaiDuWangPanController {
31 private final Logger logger = LoggerFactory.getLogger(this.getClass()); 31 private final Logger logger = LoggerFactory.getLogger(this.getClass());
32 - private static String typestr = "BaiDuWangPanToken_ZL";  
33 32
34 @ApiOperation("获取授权连接") 33 @ApiOperation("获取授权连接")
35 @GetMapping("/getOauth2Url") 34 @GetMapping("/getOauth2Url")
@@ -69,7 +68,7 @@ public class BaiDuWangPanController { @@ -69,7 +68,7 @@ public class BaiDuWangPanController {
69 68
70 try { 69 try {
71 SysTripartitePlatformToken sysTripartitePlatformToken = new SysTripartitePlatformToken(); 70 SysTripartitePlatformToken sysTripartitePlatformToken = new SysTripartitePlatformToken();
72 - sysTripartitePlatformToken.setTripartite_platform_type(typestr); 71 + sysTripartitePlatformToken.setTripartite_platform_type(BaiDuWangPanService.typestr);
73 sysTripartitePlatformToken.setTripartite_platform_name("百度网络的授权token(钟来的)"); 72 sysTripartitePlatformToken.setTripartite_platform_name("百度网络的授权token(钟来的)");
74 sysTripartitePlatformToken.setCreate_time(DateUtils.getNowTimeMilly()); 73 sysTripartitePlatformToken.setCreate_time(DateUtils.getNowTimeMilly());
75 sysTripartitePlatformToken.setUpdate_time(DateUtils.getNowTimeMilly()); 74 sysTripartitePlatformToken.setUpdate_time(DateUtils.getNowTimeMilly());
@@ -91,7 +90,7 @@ public class BaiDuWangPanController { @@ -91,7 +90,7 @@ public class BaiDuWangPanController {
91 public Message getToekn() 90 public Message getToekn()
92 { 91 {
93 try { 92 try {
94 - Entity entity = Db.use().get("sys_tripartite_platform_token","tripartite_platform_type",typestr); 93 + Entity entity = Db.use().get("sys_tripartite_platform_token","tripartite_platform_type",BaiDuWangPanService.typestr);
95 if(null == entity) 94 if(null == entity)
96 { 95 {
97 return new Message(MessageCode.DEFAULT_FAIL_CODE,"未授权"); 96 return new Message(MessageCode.DEFAULT_FAIL_CODE,"未授权");
@@ -110,6 +109,7 @@ public class BaiDuWangPanController { @@ -110,6 +109,7 @@ public class BaiDuWangPanController {
110 sysTripartitePlatformToken.setRefresh_token_end_time(sysTripartitePlatformToken.getUpdate_time()+(10*365*24*60*60)); 109 sysTripartitePlatformToken.setRefresh_token_end_time(sysTripartitePlatformToken.getUpdate_time()+(10*365*24*60*60));
111 sysTripartitePlatformToken.setUpdate_time(DateUtils.getNowTimeMilly()); 110 sysTripartitePlatformToken.setUpdate_time(DateUtils.getNowTimeMilly());
112 Db.use().update(Entity.create().parse(sysTripartitePlatformToken).setTableName("sys_tripartite_platform_token"),Entity.create().addFieldNames("id")); 111 Db.use().update(Entity.create().parse(sysTripartitePlatformToken).setTableName("sys_tripartite_platform_token"),Entity.create().addFieldNames("id"));
  112 + return new Message(MessageCode.DEFAULT_SUCCESS_CODE,sysTripartitePlatformToken.getAccess_token());
113 } 113 }
114 return new Message(MessageCode.DEFAULT_FAIL_CODE,"授权到期,请重新授权"); 114 return new Message(MessageCode.DEFAULT_FAIL_CODE,"授权到期,请重新授权");
115 } 115 }
  1 +package com.zhonglai.luhui.data.file.service.dto;
  2 +
  3 +import com.google.gson.JsonObject;
  4 +import lombok.Data;
  5 +
  6 +import java.util.Map;
  7 +
  8 +@Data
  9 +public class BaiduFileInfo {
  10 + private Long fs_id; //uint64; //文件在云端的唯一标识ID
  11 + private String path; //string; //文件的绝对路径
  12 + private String server_filename; //string; //文件名称
  13 + private Integer size; //uint; //文件大小,单位B
  14 + private Integer server_mtime; //uint; //文件在服务器修改时间
  15 + private Integer server_ctime; //uint; //文件在服务器创建时间
  16 + private Integer local_mtime; //uint; //文件在客户端修改时间
  17 + private Integer local_ctime; //uint; //文件在客户端创建时间
  18 + private Integer isdir; //uint; //是否为目录,0 文件、1 目录
  19 + private Integer category; //uint; //文件类型,1 视频、2 音频、3 图片、4 文档、5 应用、6 其他、7 种子
  20 + private String md5; //string; //云端哈希(非文件真实MD5),只有是文件类型时,该字段才存在
  21 + private Integer dir_empty; //int; //该目录是否存在子目录,只有请求参数web=1且该条目为目录时,该字段才存在, 0为存在, 1为不存在
  22 + private Map<String,String> thumbs; //array; //只有请求参数web=1且该条目分类为图片时,该字段才存在,包含三个尺寸的缩略图URL
  23 +}
  1 +package com.zhonglai.luhui.data.file.service.util;
  2 +
  3 +import cn.hutool.core.io.IORuntimeException;
  4 +import cn.hutool.core.io.IoUtil;
  5 +import cn.hutool.core.io.file.FileWriter;
  6 +import cn.hutool.core.util.CharsetUtil;
  7 +import cn.hutool.db.Db;
  8 +import cn.hutool.db.Entity;
  9 +import com.zhonglai.luhui.data.file.service.baidu.BaiDuWangPanService;
  10 +import com.zhonglai.luhui.data.file.service.dto.BaiduFileInfo;
  11 +import org.apache.commons.lang3.ArrayUtils;
  12 +import org.apache.commons.lang3.time.DateFormatUtils;
  13 +
  14 +import java.io.*;
  15 +import java.net.URLEncoder;
  16 +import java.sql.SQLException;
  17 +import java.util.*;
  18 +import java.util.concurrent.TimeUnit;
  19 +
  20 +/**
  21 + * 文件工具
  22 + */
  23 +public class FileUtil {
  24 + private static String LvLianFilePath = "D:/data/ly_sensor_data";
  25 + private static String BaiDuWangPanFilePath = "/禄辉/ly_sensor_data";
  26 + private static String tempFilePath = "D:/data";
  27 + private static String CRLF = "\r\n";
  28 + /**
  29 + * 读取绿联云的文件
  30 + * @param lvLianFilePath
  31 + */
  32 + public static void readLvLianFile(String lvLianFilePath)
  33 + {
  34 + File file = new File(lvLianFilePath);
  35 + if(file.exists())
  36 + {
  37 + File[] devices = file.listFiles();
  38 + if(null != devices && devices.length !=0)
  39 + {
  40 + for (File device:devices)
  41 + {
  42 + ScheduledUtil.scheduler.schedule(() -> {
  43 + System.out.println("读取到设备数据文件夹:"+device.getAbsolutePath());
  44 + File[] sentDevice = device.listFiles();
  45 + for (File sentD:sentDevice)
  46 + {
  47 + ScheduledUtil.scheduler.schedule(() -> {
  48 + readLvLianDataFileToBaiduDataFile(sentD);
  49 + },0,TimeUnit.SECONDS);
  50 + }
  51 +
  52 +
  53 + },1, TimeUnit.SECONDS);
  54 +
  55 + }
  56 + while (ScheduledUtil.scheduler.isShutdown())
  57 + {
  58 + return;
  59 + }
  60 + }
  61 + }
  62 + }
  63 +
  64 + /**
  65 + * 创建百度网盘存放路径
  66 + * @return
  67 + */
  68 + public static String createBaiduWangPanPat(String yea,String deviceType,String imei,String deviceInfoId,String dataType)
  69 + {
  70 + return new StringBuffer(BaiDuWangPanFilePath).append("/").append(yea).append("/").append(deviceType).append("/").append(imei).append("/").append(deviceInfoId).append("-").append(dataType).append(".csv").toString();
  71 + }
  72 +
  73 + /**
  74 + * 读取绿联云的数据文件,并且拆分成百度存储的数据文件
  75 + */
  76 + public static void readLvLianDataFileToBaiduDataFile(File lvLianDataFile)
  77 + {
  78 + if(null != lvLianDataFile && lvLianDataFile.exists()&& lvLianDataFile.isFile())
  79 + {
  80 + String name = lvLianDataFile.getName();
  81 + String imei = lvLianDataFile.getParentFile().getName();
  82 + String deviceInfoId = name.substring(0,name.indexOf("-"));
  83 + String dataType = name.substring(name.indexOf("-")+1,name.indexOf("."));
  84 + String deviceType = deviceTypeMap.get(imei);
  85 + String time = "";
  86 + BufferedReader reader = null;
  87 + BufferedWriter bufferedWriter = null;
  88 + try {
  89 + reader = cn.hutool.core.io.FileUtil.getReader(lvLianDataFile, "UTF-8");
  90 + String line;
  91 + while (true) {
  92 + line = reader.readLine();
  93 + if (line == null) {
  94 + break;
  95 + }
  96 + String[] ds = line.split(",");
  97 +
  98 + if(null != ds && ds.length==2)
  99 + {
  100 + String yea = DateFormatUtils.format(new Date(Integer.valueOf(ds[0])*1000l), "yyyy");
  101 + if(!yea.equals(time))
  102 + {
  103 + time = yea;
  104 + String baiduPath = createBaiduWangPanPat(yea,null==deviceType?"device_model":deviceType,imei,deviceInfoId,dataType);
  105 + File file = new File(tempFilePath+baiduPath);
  106 + bufferedWriter = FileWriter.create(file, CharsetUtil.CHARSET_UTF_8).getWriter(true);
  107 + }
  108 + if (null != bufferedWriter)
  109 + {
  110 + bufferedWriter.write(line);
  111 + //默认换行符
  112 + bufferedWriter.write(CRLF);
  113 + bufferedWriter.flush();
  114 + }
  115 + }
  116 + }
  117 + } catch (IOException e) {
  118 + throw new IORuntimeException(e);
  119 + } finally {
  120 + IoUtil.close(reader);
  121 + IoUtil.close(bufferedWriter);
  122 + }
  123 + }
  124 + }
  125 +
  126 + public static void initDeviceType()
  127 + {
  128 + try {
  129 + List<Entity> list = Db.use().query("select device_model,id from device_host");
  130 + if(null != list && list.size() !=0 )
  131 + {
  132 + for (Entity entity:list)
  133 + {
  134 + deviceTypeMap.put(entity.getStr("id"),entity.get("device_model","device_model"));
  135 + }
  136 + }
  137 + } catch (SQLException e) {
  138 + System.err.println(e);
  139 + }
  140 + }
  141 +
  142 + static Map<String,String> deviceTypeMap = new HashMap<>();
  143 +
  144 + public static void main(String[] args) {
  145 + initDeviceType();
  146 + readLvLianFile("D:/data/ly_sensor_data");
  147 + }
  148 +
  149 +}
  1 +package com.zhonglai.luhui.data.file.service.util;
  2 +
  3 +import java.util.concurrent.Executors;
  4 +import java.util.concurrent.ScheduledExecutorService;
  5 +
  6 +public class ScheduledUtil {
  7 +
  8 + public final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(20);
  9 +
  10 +}
1 -url=jdbc:mysql://rm-wz9740un21f09iokuao.mysql.rds.aliyuncs.com:3306/mqtt_broker?useUnicode=true&characterEncoding=utf8&autoReconnect=true 1 +url=jdbc:mysql://rm-wz9740un21f09iokuao.mysql.rds.aliyuncs.com:3306/liu_yu_le?useUnicode=true&characterEncoding=utf8&autoReconnect=true
2 user = luhui 2 user = luhui
3 pass = Luhui586 3 pass = Luhui586
4 4
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <modelVersion>4.0.0</modelVersion>
  6 + <parent>
  7 + <groupId>com.zhonglai.luhui</groupId>
  8 + <artifactId>lh-modules</artifactId>
  9 + <version>1.0-SNAPSHOT</version>
  10 + </parent>
  11 +
  12 + <artifactId>lh-lsy-plc-service</artifactId>
  13 +
  14 + <properties>
  15 + <maven.compiler.source>8</maven.compiler.source>
  16 + <maven.compiler.target>8</maven.compiler.target>
  17 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  18 + </properties>
  19 +
  20 + <dependencies>
  21 + <!-- spring-boot-devtools -->
  22 + <dependency>
  23 + <groupId>org.springframework.boot</groupId>
  24 + <artifactId>spring-boot-devtools</artifactId>
  25 + <optional>true</optional> <!-- 表示依赖不会传递 -->
  26 + </dependency>
  27 + <!-- SpringBoot Web容器 -->
  28 + <dependency>
  29 + <groupId>org.springframework.boot</groupId>
  30 + <artifactId>spring-boot-starter-web</artifactId>
  31 + </dependency>
  32 + <!-- Spring框架基本的核心工具 -->
  33 + <dependency>
  34 + <groupId>org.springframework</groupId>
  35 + <artifactId>spring-context-support</artifactId>
  36 + </dependency>
  37 + <!-- SpringWeb模块 -->
  38 + <dependency>
  39 + <groupId>org.springframework</groupId>
  40 + <artifactId>spring-web</artifactId>
  41 + </dependency>
  42 + <!-- yml解析器 -->
  43 + <dependency>
  44 + <groupId>org.yaml</groupId>
  45 + <artifactId>snakeyaml</artifactId>
  46 + </dependency>
  47 + <!-- servlet包 -->
  48 + <dependency>
  49 + <groupId>javax.servlet</groupId>
  50 + <artifactId>javax.servlet-api</artifactId>
  51 + </dependency>
  52 + <dependency>
  53 + <groupId>org.apache.commons</groupId>
  54 + <artifactId>commons-text</artifactId>
  55 + </dependency>
  56 +
  57 + <!-- 文档 -->
  58 + <dependency>
  59 + <groupId>io.springfox</groupId>
  60 + <artifactId>springfox-swagger2</artifactId>
  61 + <version>${swagger.version}</version>
  62 + <exclusions>
  63 + <exclusion>
  64 + <groupId>io.swagger</groupId>
  65 + <artifactId>swagger-models</artifactId>
  66 + </exclusion>
  67 + <exclusion>
  68 + <groupId>com.google.guava</groupId>
  69 + <artifactId>guava</artifactId>
  70 + </exclusion>
  71 + </exclusions>
  72 + </dependency>
  73 + <!--https://mvnrepository.com/artifact/io.swagger/swagger-models-->
  74 + <dependency>
  75 + <groupId>io.swagger</groupId>
  76 + <artifactId>swagger-models</artifactId>
  77 + <version>${swagger-models.version}</version>
  78 + </dependency>
  79 + <dependency>
  80 + <groupId>io.springfox</groupId>
  81 + <artifactId>springfox-swagger-ui</artifactId>
  82 + <version>${swagger.version}</version>
  83 + </dependency>
  84 + <!--&lt;!&ndash; https://mvnrepository.com/artifact/com.github.xiaoymin/swagger-bootstrap-ui &ndash;&gt;-->
  85 + <dependency>
  86 + <groupId>com.github.xiaoymin</groupId>
  87 + <artifactId>swagger-bootstrap-ui</artifactId>
  88 + <version>${swagger-ui.version}</version>
  89 + </dependency>
  90 +
  91 +
  92 + <!-- 支持data -->
  93 + <dependency>
  94 + <groupId>org.projectlombok</groupId>
  95 + <artifactId>lombok</artifactId>
  96 + </dependency>
  97 +
  98 +
  99 + <!-- 阿里JSON解析器 -->
  100 + <dependency>
  101 + <groupId>com.alibaba</groupId>
  102 + <artifactId>fastjson</artifactId>
  103 + </dependency>
  104 +
  105 + <!--常用工具类 -->
  106 + <dependency>
  107 + <groupId>org.apache.commons</groupId>
  108 + <artifactId>commons-lang3</artifactId>
  109 + </dependency>
  110 +
  111 +
  112 + <!-- 通用工具-->
  113 + <dependency>
  114 + <groupId>com.zhonglai.luhui</groupId>
  115 + <artifactId>lh-domain</artifactId>
  116 + <exclusions>
  117 + <exclusion>
  118 + <groupId>org.slf4j</groupId>
  119 + <artifactId>slf4j-simple</artifactId>
  120 + </exclusion>
  121 + </exclusions>
  122 + </dependency>
  123 +
  124 + <dependency>
  125 + <groupId>com.zhonglai.luhui</groupId>
  126 + <artifactId>lh-jar-device-service</artifactId>
  127 + <scope>compile</scope>
  128 + </dependency>
  129 + <dependency>
  130 + <groupId>com.zhonglai.luhui</groupId>
  131 + <artifactId>lh-jar-device-analysis</artifactId>
  132 + <scope>compile</scope>
  133 + </dependency>
  134 +
  135 + </dependencies>
  136 +
  137 + <build>
  138 + <finalName>lh-lsy-plc-service</finalName>
  139 + <plugins>
  140 + <plugin>
  141 + <groupId>org.apache.maven.plugins</groupId>
  142 + <artifactId>maven-jar-plugin</artifactId>
  143 + <version>2.4</version>
  144 + <configuration>
  145 + <archive>
  146 + <!--
  147 + 生成的jar中,不要包含pom.xml和pom.properties这两个文件
  148 + -->
  149 + <addMavenDescriptor>false</addMavenDescriptor>
  150 + <manifest>
  151 + <!--
  152 + 是否要把第三方jar放到manifest的classpath中
  153 + -->
  154 + <addClasspath>true</addClasspath>
  155 +
  156 + <!--
  157 + 生成的manifest中classpath的前缀,因为要把第三方jar放到lib目录下,所以classpath的前缀是lib/
  158 + -->
  159 + <classpathPrefix>lib/</classpathPrefix>
  160 + <mainClass>com.zhonglai.luhui.lsy.plc.service.Main</mainClass>
  161 + </manifest>
  162 + </archive>
  163 + </configuration>
  164 + </plugin>
  165 +
  166 + <!-- The configuration of maven-assembly-plugin -->
  167 + <plugin>
  168 + <groupId>org.apache.maven.plugins</groupId>
  169 + <artifactId>maven-assembly-plugin</artifactId>
  170 + <version>2.4</version>
  171 + <configuration>
  172 + <descriptors>
  173 + <descriptor>src/main/resources/package.xml</descriptor>
  174 + </descriptors>
  175 + </configuration>
  176 + <executions>
  177 + <execution>
  178 + <id>make-assembly</id>
  179 + <phase>package</phase>
  180 + <goals>
  181 + <goal>single</goal>
  182 + </goals>
  183 + </execution>
  184 + </executions>
  185 + </plugin>
  186 + </plugins>
  187 + </build>
  188 +
  189 +</project>
  1 +package com.zhonglai.luhui.lsy.plc.service;
  2 +
  3 +import com.zhonglai.luhui.lsy.plc.service.dto.DeviceProductProtocol;
  4 +import org.slf4j.Logger;
  5 +import org.slf4j.LoggerFactory;
  6 +import org.springframework.boot.autoconfigure.SpringBootApplication;
  7 +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
  8 +import org.springframework.boot.builder.SpringApplicationBuilder;
  9 +import org.springframework.context.annotation.ComponentScan;
  10 +
  11 +@ComponentScan(basePackages = {
  12 + "com.zhonglai.luhui.device.analysis.comm.agreement",
  13 + "com.zhonglai.luhui.device.analysis.comm.config",
  14 + "com.zhonglai.luhui.lsy.plc.service",
  15 +})
  16 +@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
  17 +public class Main {
  18 +
  19 + private static Logger log = LoggerFactory.getLogger(Main.class);
  20 + public static void main(String[] args) {
  21 + log.info("启动服务");
  22 +// System.setProperty("dbPath","E:/work/idea/Luhui/lh-modules/lh-lsy-plc-service/src/main/resources/");
  23 + DeviceProductProtocol.init();
  24 + SpringApplicationBuilder builder = new SpringApplicationBuilder(Main.class);
  25 + builder.run( args);
  26 + }
  27 +
  28 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.comm.service;
  2 +
  3 +import com.alibaba.fastjson.JSONObject;
  4 +import com.zhonglai.luhui.device.analysis.dto.ApiName;
  5 +import com.zhonglai.luhui.device.analysis.dto.DeviceCommandApiParameter;
  6 +import com.zhonglai.luhui.device.analysis.dto.Message;
  7 +import com.zhonglai.luhui.device.analysis.dto.MessageCode;
  8 +import com.zhonglai.luhui.device.domain.IotDevice;
  9 +import com.zhonglai.luhui.device.domain.IotTerminal;
  10 +import org.eclipse.paho.client.mqttv3.MqttException;
  11 +
  12 +/**
  13 + * 设备指令接口
  14 + */
  15 +public class DeviceCommandApi {
  16 + private ApiName apiName; //指令接口名称
  17 + private DeviceCommandApiParameter deviceCommandApiParameter; //参数
  18 +
  19 + public Message invokeApi(MqttDeviceService deviceService) throws InterruptedException, MqttException {
  20 + switch (apiName)
  21 + {
  22 +// case read:
  23 +// return deviceService.read(deviceCommandApiParameter.getClient_id(),deviceCommandApiParameter.getMap());
  24 +// case control:
  25 +// return deviceService.control(deviceCommandApiParameter.getClient_id(), deviceCommandApiParameter.getMap());
  26 +// case controlHex:
  27 +// return deviceService.controlHex(deviceCommandApiParameter.getClient_id(),deviceCommandApiParameter.getData());
  28 +// case closeSession:
  29 +// return deviceService.closeSession(deviceCommandApiParameter.getClient_id());
  30 +// case delIotDevice:
  31 +// deviceService.closeSession(deviceCommandApiParameter.getClient_id()); //强制下线
  32 +// return deviceService.delIotDevice(deviceCommandApiParameter.getClient_id());
  33 +// case delIotTerminal:
  34 +// deviceService.closeSession(deviceCommandApiParameter.getClient_id()); //强制下线
  35 +// return deviceService.delIotTerminal(deviceCommandApiParameter.getClient_id(),deviceCommandApiParameter.getNumber());
  36 +// case getFirmwareVersion:
  37 +// return deviceService.getFirmwareVersion(deviceCommandApiParameter.getData());
  38 +// case updateIotDevice:
  39 +// IotDevice iotDevice = JSONObject.parseObject(JSONObject.toJSONString(deviceCommandApiParameter.getMap()), IotDevice.class);
  40 +// deviceCommandApiParameter.setClient_id(iotDevice.getClient_id());
  41 +// return deviceService.updateIotDevice(iotDevice);
  42 +// case updateIotTerminal:
  43 +// IotTerminal iotTerminal = JSONObject.parseObject(JSONObject.toJSONString(deviceCommandApiParameter.getMap()), IotTerminal.class);
  44 +// deviceCommandApiParameter.setClient_id(iotTerminal.getId());
  45 +// return deviceService.updateIotTerminal(iotTerminal);
  46 +// case delDeviceHost:
  47 +// return deviceService.delDeviceHost(deviceCommandApiParameter.getClient_id());
  48 +// case delDeviceInfo:
  49 +// deviceCommandApiParameter.setClient_id(deviceCommandApiParameter.getData());
  50 +// return deviceService.delDeviceInfo(deviceCommandApiParameter.getData());
  51 +// case delDeviceInfoFromDeviceId:
  52 +// return deviceService.delDeviceInfoFromDeviceId(deviceCommandApiParameter.getClient_id());
  53 +// case transferPond:
  54 +// return deviceService.transferPond(deviceCommandApiParameter.getClient_id(),deviceCommandApiParameter.getMap());
  55 +// case updateDeviceInfo:
  56 +// return deviceService.updateDeviceInfo(deviceCommandApiParameter.getClient_id(),deviceCommandApiParameter.getMap());
  57 + default:
  58 + return new Message(MessageCode.DEFAULT_FAIL_CODE,"接口不存在");
  59 + }
  60 +
  61 + }
  62 +
  63 + public ApiName getApiName() {
  64 + return apiName;
  65 + }
  66 +
  67 + public void setApiName(ApiName apiName) {
  68 + this.apiName = apiName;
  69 + }
  70 +
  71 + public DeviceCommandApiParameter getDeviceCommandApiParameter() {
  72 + return deviceCommandApiParameter;
  73 + }
  74 +
  75 + public void setDeviceCommandApiParameter(DeviceCommandApiParameter deviceCommandApiParameter) {
  76 + this.deviceCommandApiParameter = deviceCommandApiParameter;
  77 + }
  78 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.comm.service;
  2 +
  3 +import com.zhonglai.luhui.device.analysis.comm.dao.BaseDao;
  4 +import com.zhonglai.luhui.lsy.plc.service.dto.DeviceInfo;
  5 +import com.zhonglai.luhui.lsy.plc.service.dto.LogDeviceOperation;
  6 +import com.zhonglai.luhui.lsy.plc.service.dto.OrderDtu;
  7 +import org.springframework.stereotype.Service;
  8 +
  9 +import java.util.HashMap;
  10 +import java.util.List;
  11 +import java.util.Map;
  12 +
  13 +@Service
  14 +public class DeviceService {
  15 + private static BaseDao baseDao = new BaseDao();
  16 +
  17 + /**
  18 + * 获取设备
  19 + * @param imei
  20 + * @return
  21 + */
  22 + public OrderDtu getOrderDtu(String imei)
  23 + {
  24 + Map<String,Object> where = new HashMap<>();
  25 + where.put("orderDtuImei",imei);
  26 + return (OrderDtu) baseDao.get(OrderDtu.class,where);
  27 + }
  28 +
  29 + /**
  30 + * 获取设备
  31 + * @param id
  32 + * @return
  33 + */
  34 + public DeviceInfo getDeviceInfo(String id)
  35 + {
  36 + Map<String,Object> where = new HashMap<>();
  37 + where.put("id",id);
  38 + return (DeviceInfo) baseDao.get(DeviceInfo.class,where);
  39 + }
  40 +
  41 + /**
  42 + * 获取设备
  43 + * @return
  44 + */
  45 + public List<DeviceInfo> getDeviceInfoList(String imei)
  46 + {
  47 + return baseDao.findBysql("SELECT `id`,alarm_code,data_value,device_service_ip FROM `device_info` WHERE `id` LIKE '%"+imei+"%'", DeviceInfo.class);
  48 + }
  49 +
  50 +
  51 + /**
  52 + * 获取设备
  53 + * @return
  54 + */
  55 + public void upDeviceInfo(DeviceInfo deviceInfo)
  56 + {
  57 + baseDao.update(deviceInfo);
  58 + }
  59 +
  60 + /**
  61 + * 获取设备
  62 + * @return
  63 + */
  64 + public void addloglist(List<LogDeviceOperation> logDeviceOperationList,String tableName)
  65 + {
  66 + baseDao.insertList(logDeviceOperationList, tableName);
  67 + }
  68 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.comm.service;
  2 +
  3 +import com.zhonglai.luhui.device.analysis.comm.dto.ServerDto;
  4 +import com.zhonglai.luhui.device.analysis.comm.dto.business.BusinessDto;
  5 +import com.zhonglai.luhui.device.analysis.comm.dto.business.BusinessDtoClassNew;
  6 +import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreement;
  7 +import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreementFactory;
  8 +import com.zhonglai.luhui.device.analysis.comm.factory.Topic;
  9 +import com.zhonglai.luhui.device.analysis.comm.util.ByteUtil;
  10 +import com.zhonglai.luhui.lsy.plc.service.comm.util.TopicUtil;
  11 +import com.zhonglai.luhui.lsy.plc.service.dto.AllPostDto;
  12 +import com.zhonglai.luhui.lsy.plc.service.dto.DeviceProductProtocol;
  13 +import com.zhonglai.luhui.lsy.plc.service.dto.OrderDtu;
  14 +import com.zhonglai.luhui.lsy.plc.service.service.PLCDataPersistenceService;
  15 +import lombok.SneakyThrows;
  16 +import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
  17 +import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
  18 +import org.eclipse.paho.client.mqttv3.MqttException;
  19 +import org.eclipse.paho.client.mqttv3.MqttMessage;
  20 +import org.slf4j.Logger;
  21 +import org.slf4j.LoggerFactory;
  22 +import org.springframework.beans.factory.annotation.Autowired;
  23 +import org.springframework.stereotype.Component;
  24 +
  25 +
  26 +@Component
  27 +public class MqttCallback implements MqttCallbackExtended {
  28 + private static final Logger log = LoggerFactory.getLogger(MqttCallback.class);
  29 + @Autowired
  30 + private BusinessAgreementFactory businessAgreementFactory;
  31 + @Autowired
  32 + private TerminalService terminalService; //客户端服务
  33 +
  34 + @Autowired
  35 + private DeviceService deviceService;
  36 +
  37 + @Autowired
  38 + private PLCDataPersistenceService plcDataPersistenceService;
  39 +
  40 +
  41 + @SneakyThrows
  42 + @Override
  43 + public void connectComplete(boolean b, String s) {
  44 + // 连接成功
  45 + log.info("连接成功");
  46 + terminalService.subscribe();
  47 + }
  48 +
  49 + @Override
  50 + public void connectionLost(Throwable throwable) {
  51 + //连接丢失
  52 + log.error("连接丢失",throwable);
  53 +
  54 + }
  55 +
  56 + @Override
  57 + public void messageArrived(String s, MqttMessage mqttMessage) {
  58 + Topic desttopic = TopicUtil.initTopic(s);
  59 + desttopic.setTopicType("POST_REQ");
  60 + //接收到消息
  61 + StringBuffer buffer = new StringBuffer();
  62 + buffer.append("topic:");
  63 + buffer.append(s);
  64 + buffer.append("\r\n");
  65 + buffer.append("mqttMessage字符串:");
  66 + buffer.append(mqttMessage.toString());
  67 + buffer.append("\r\n");
  68 + buffer.append("mqttMessage十六进制:");
  69 + buffer.append(ByteUtil.hexStringToSpace(ByteUtil.toHexString(mqttMessage.getPayload())));
  70 + buffer.append("\r\n");
  71 + buffer.append("\r\n");
  72 +
  73 + try {
  74 + Topic topic = TopicUtil.initTopic(s);
  75 + if(null == topic)
  76 + {
  77 + log.error("消息{},topic为空,不做解析");
  78 + log.error("消息《"+s+"》解析为空 》》》内容:\r\n"+buffer.toString());
  79 + return;
  80 + }
  81 +
  82 + //日志记录
  83 + log.info(buffer.toString());
  84 +
  85 + //准备数据
  86 + byte[] data = mqttMessage.getPayload();
  87 + OrderDtu orderDtu = deviceService.getOrderDtu(topic.getClientid());
  88 + if(null == orderDtu)
  89 + {
  90 + log.info("设备dtu{}不存在",topic.getClientid());
  91 + return;
  92 + }
  93 +
  94 + //转化为协议对象
  95 + BusinessDto businessDto = BusinessDtoClassNew.newBean(DeviceProductProtocol.payloadtype,data).analyticalModel(null);
  96 +
  97 + BusinessAgreement businessAgreement = businessAgreementFactory.createBusinessAgreement(topic);
  98 + //解析为业务对象
  99 + ServerDto dto = businessAgreement.analysis(topic,businessAgreement.toData(businessDto));
  100 + if(null == dto)
  101 + {
  102 + return;
  103 + }
  104 + log.info("{} 解析到的dto【{}】",dto);
  105 +
  106 + //数据持久化
  107 + plcDataPersistenceService.persistence(topic, dto);
  108 +
  109 + log.info("{} payload解析完成",s);
  110 + } catch (Exception e) {
  111 + log.error(s+"消息解析异常",e);
  112 +
  113 + }
  114 + }
  115 +
  116 + @Override
  117 + public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
  118 + // 成功发出消息
  119 + try {
  120 + log.info("成功发出消息 messageid{}",iMqttDeliveryToken.getMessage());
  121 + } catch (MqttException e) {
  122 + e.printStackTrace();
  123 + }
  124 + }
  125 +
  126 + public MqttCallback binldTerminalService(TerminalService terminalService)
  127 + {
  128 + this.terminalService = terminalService;
  129 + return this;
  130 + }
  131 +
  132 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.comm.service;
  2 +
  3 +import com.alibaba.fastjson.JSON;
  4 +import com.alibaba.fastjson.JSONObject;
  5 +import com.zhonglai.luhui.device.analysis.comm.db.DeviceService;
  6 +import com.zhonglai.luhui.device.analysis.comm.db.mode.TerminalDataThingsModeService;
  7 +import com.zhonglai.luhui.device.analysis.comm.dto.LogDeviceOperation;
  8 +import com.zhonglai.luhui.device.analysis.comm.dto.thingsmodels.ThingsModelBase;
  9 +import com.zhonglai.luhui.device.analysis.comm.dto.thingsmodels.ThingsModelDataTypeEnum;
  10 +import com.zhonglai.luhui.device.analysis.comm.dto.thingsmodels.ThingsModelItemBase;
  11 +import com.zhonglai.luhui.device.analysis.comm.factory.Topic;
  12 +import com.zhonglai.luhui.device.analysis.comm.service.BusinessDataUpdateService;
  13 +import com.zhonglai.luhui.device.analysis.comm.service.CacheServiceImpl;
  14 +import com.zhonglai.luhui.device.analysis.comm.service.DataPersistenceServiceImpl;
  15 +import com.zhonglai.luhui.device.analysis.comm.service.DeviceLogService;
  16 +import com.zhonglai.luhui.device.analysis.comm.util.DateUtils;
  17 +import com.zhonglai.luhui.device.analysis.dto.Message;
  18 +import com.zhonglai.luhui.device.analysis.dto.MessageCode;
  19 +import com.zhonglai.luhui.device.analysis.dto.topic.AddPostDto;
  20 +import com.zhonglai.luhui.device.domain.IotThingsModel;
  21 +import com.zhonglai.luhui.lsy.plc.service.service.ClienNoticeService;
  22 +import org.eclipse.paho.client.mqttv3.MqttException;
  23 +import org.eclipse.paho.client.mqttv3.MqttMessage;
  24 +import org.slf4j.Logger;
  25 +import org.slf4j.LoggerFactory;
  26 +import org.springframework.beans.factory.annotation.Autowired;
  27 +import org.springframework.stereotype.Service;
  28 +
  29 +import java.util.ArrayList;
  30 +import java.util.List;
  31 +import java.util.Map;
  32 +
  33 +@Service
  34 +public class MqttDeviceService {
  35 + private static final Logger log = LoggerFactory.getLogger(MqttDeviceService.class);
  36 + @Autowired
  37 + private ClienNoticeService clienNoticeService;
  38 +
  39 +
  40 +
  41 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.comm.service;
  2 +
  3 +import com.zhonglai.luhui.device.analysis.comm.config.SysParameter;
  4 +import com.zhonglai.luhui.device.analysis.comm.factory.Topic;
  5 +import com.zhonglai.luhui.device.analysis.comm.service.DataModeAnalysisService;
  6 +import com.zhonglai.luhui.lsy.plc.service.comm.util.TopicUtil;
  7 +import org.apache.commons.lang3.StringUtils;
  8 +import org.eclipse.paho.client.mqttv3.MqttClient;
  9 +import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
  10 +import org.eclipse.paho.client.mqttv3.MqttException;
  11 +import org.eclipse.paho.client.mqttv3.MqttMessage;
  12 +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
  13 +import org.slf4j.Logger;
  14 +import org.slf4j.LoggerFactory;
  15 +import org.springframework.beans.factory.annotation.Autowired;
  16 +import org.springframework.beans.factory.annotation.Value;
  17 +import org.springframework.stereotype.Service;
  18 +
  19 +import javax.annotation.PostConstruct;
  20 +import java.nio.ByteBuffer;
  21 +import java.nio.charset.Charset;
  22 +import java.util.ArrayList;
  23 +import java.util.List;
  24 +import java.util.concurrent.ExecutorService;
  25 +import java.util.concurrent.LinkedBlockingQueue;
  26 +import java.util.concurrent.ThreadPoolExecutor;
  27 +import java.util.concurrent.TimeUnit;
  28 +
  29 +/**
  30 + * 终端服务
  31 + */
  32 +@Service
  33 +public class TerminalService {
  34 + private static final Logger log = LoggerFactory.getLogger(TerminalService.class);
  35 + @Autowired
  36 + private MqttCallback mqttCallback;
  37 +
  38 + @Autowired
  39 + private SysParameter sysParameter;
  40 +
  41 + @Value("${mqtt.broker}")
  42 + private String broker;
  43 + @Value("${mqtt.clientId}")
  44 + private String clientId;
  45 + @Value("${mqtt.roleid}")
  46 + private String roleid;
  47 + @Value("#{'${mqtt.mqtt_usernames}'.split(',')}")
  48 + private List<String> mqtt_usernames;
  49 + @Value("#{'${mqtt.topics}'.split(',')}")
  50 + private List<String> topics;
  51 + @Value("${mqtt.username}")
  52 + private String username;
  53 + @Value("${mqtt.sub_clientid}")
  54 + private String sub_clientid;
  55 + @Value("${mqtt.password}")
  56 + private String password;
  57 + @Value("${mqtt.topicconfig}")
  58 + private String topicconfig;
  59 +
  60 + private MqttClient mqttclient;
  61 +
  62 + private MqttConnectOptions options;
  63 +
  64 + private void init() throws MqttException {
  65 + if(null == mqttclient)
  66 + {
  67 + mqttclient = new MqttClient(broker, clientId, new MemoryPersistence());
  68 + }
  69 + options = new MqttConnectOptions();
  70 + options.setCleanSession(true);
  71 + options.setConnectionTimeout(15);
  72 + //设置断开后重新连接
  73 + options.setAutomaticReconnect(true);
  74 + mqttclient.setCallback(mqttCallback.binldTerminalService(this));
  75 + }
  76 +
  77 + private void connect() throws MqttException {
  78 + options.setUserName(username);
  79 + options.setPassword(password.toCharArray());
  80 + mqttclient.connect(options);
  81 + }
  82 +
  83 + public void subscribe() throws MqttException {
  84 + List<String> ts = getCompletionTopics();
  85 + mqttclient.subscribe(ts.toArray(new String[ts.size()]));
  86 + }
  87 +
  88 + public List<String> getCompletionTopics()
  89 + {
  90 + List<String> ts = new ArrayList<>();
  91 + for(String mqtt_username:mqtt_usernames)
  92 + {
  93 + for(String tc:topics)
  94 + {
  95 + String topic = topicconfig.replace("{{roleid}}",roleid).replace("{{username}}",mqtt_username).replace("{{clientid}}",sub_clientid).replace("{{topicType}}",tc);
  96 +
  97 + ts.add(topic);
  98 + }
  99 + }
  100 + return ts;
  101 + }
  102 +
  103 + @PostConstruct
  104 + public void startMqttListenerService() throws MqttException {
  105 + log.info("-----------开始启动mqtt监听服务--------------------");
  106 + init();
  107 + log.info("-----------启动参数{}--------------------",options);
  108 + sysParameter.inittopicconfig();
  109 + log.info("-----------终端数据模型配置成功--------------------");
  110 + connect();
  111 + log.info("-----------mqtt连接服务器成功--------------------");
  112 + subscribe();
  113 + log.info("-----------订阅{}:{}成功--------------------",sub_clientid,topics);
  114 +
  115 + }
  116 +
  117 + public void publish(String topic, MqttMessage message) throws MqttException {
  118 + mqttclient.publish(topic,message);
  119 + }
  120 +
  121 + public void publish(String topic, String messageStr) throws MqttException {
  122 + MqttMessage message = new MqttMessage();
  123 + message.setPayload(messageStr.getBytes());
  124 + mqttclient.publish(topic,message);
  125 + }
  126 +
  127 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.comm.util;
  2 +
  3 +import com.zhonglai.luhui.device.analysis.comm.config.SysParameter;
  4 +import com.zhonglai.luhui.device.analysis.comm.dto.MyException;
  5 +import com.zhonglai.luhui.device.analysis.comm.factory.Topic;
  6 +import com.zhonglai.luhui.device.analysis.comm.util.StringUtils;
  7 +import org.slf4j.Logger;
  8 +import org.slf4j.LoggerFactory;
  9 +
  10 +import java.lang.reflect.Field;
  11 +import java.util.Optional;
  12 +
  13 +public class TopicUtil {
  14 + private static final Logger log = LoggerFactory.getLogger(TopicUtil.class);
  15 +
  16 + public static Topic initTopic(String topic)
  17 + {
  18 + topic = Optional.ofNullable(topic).orElseThrow(()->new MyException("topic为空"));
  19 + String[] sts = topic.split("/");
  20 + String[] config = SysParameter.topicconfig.split("/");
  21 + int number = sts.length;
  22 + if(number>config.length)
  23 + {
  24 + number = config.length;
  25 + }
  26 + Topic topicObject = new Topic();
  27 + for(int i=1;i<number;i++)
  28 + {
  29 + String cf = config[i].replace("{{","").replace("}}","");
  30 + try {
  31 + Field field = topicObject.getClass().getDeclaredField(cf);
  32 + field.setAccessible(true);
  33 + field.set(topicObject,sts[i]);
  34 + } catch (NoSuchFieldException e) {
  35 + log.info("{}生成topic时没有属性{}",topic,cf);
  36 + } catch (IllegalAccessException e) {
  37 + log.info("{}生成topic时无法给{}赋值{}",topic,cf,sts[i]);
  38 + }
  39 + }
  40 + return topicObject;
  41 + }
  42 +
  43 + /**
  44 + * 生成缓存关键字
  45 + * @return
  46 + */
  47 + public static String generateRedicKey(Topic topic)
  48 + {
  49 + return generate(topic,":");
  50 + }
  51 +
  52 + /**
  53 + * 生成发送消息的topic
  54 + * @return
  55 + */
  56 + public static String generateSendMessageTopic(Topic topic)
  57 + {
  58 +
  59 + return "/"+generate(topic,"/");
  60 + }
  61 +
  62 + /**
  63 + * 生成客户端关键字
  64 + * @return
  65 + */
  66 + public static String generateClienKey(Topic topic)
  67 + {
  68 + return "/"+generate(topic,"/");
  69 + }
  70 +
  71 + private static String generate(Topic topic,String division)
  72 + {
  73 + String str = SysParameter.topicconfig;
  74 + if(StringUtils.isEmpty(topic.getRoleid()))
  75 + {
  76 + topic.setRoleid("2");
  77 + }
  78 + str = str.replace("/{{roleid}}",topic.getRoleid()+division);
  79 +
  80 + if(StringUtils.isEmpty(topic.getUsername()))
  81 + {
  82 + topic.setUsername("+");
  83 + }
  84 + str = str.replace("/{{username}}",topic.getUsername()+division);
  85 +
  86 + if(StringUtils.isEmpty(topic.getClientid()))
  87 + {
  88 + topic.setClientid( "+");
  89 + }
  90 + str = str.replace("/{{clientid}}",topic.getClientid()+division);
  91 +
  92 + if(StringUtils.isEmpty(topic.getPayloadtype()))
  93 + {
  94 + topic.setPayloadtype( "String");
  95 + }
  96 + str = str.replace("/{{payloadtype}}",topic.getPayloadtype()+division);
  97 +
  98 + if(StringUtils.isEmpty(topic.getTopicType()))
  99 + {
  100 + topic.setTopicType("PUT");
  101 + }
  102 + str = str.replace("/{{topicType}}",topic.getTopicType()+division);
  103 +
  104 + if(StringUtils.isNotEmpty(topic.getMessageid()))
  105 + {
  106 + str = str.replace("/{{messageid}}",topic.getMessageid());
  107 + }
  108 +
  109 + if (str.endsWith("/"))
  110 + {
  111 + str = str.substring(0,str.lastIndexOf("/"));
  112 + }
  113 + return str;
  114 + }
  115 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.config;
  2 +
  3 +import io.swagger.annotations.ApiOperation;
  4 +import org.springframework.context.annotation.Bean;
  5 +import org.springframework.context.annotation.Configuration;
  6 +import springfox.documentation.builders.ApiInfoBuilder;
  7 +import springfox.documentation.builders.PathSelectors;
  8 +import springfox.documentation.builders.RequestHandlerSelectors;
  9 +import springfox.documentation.service.ApiInfo;
  10 +import springfox.documentation.service.Contact;
  11 +import springfox.documentation.spi.DocumentationType;
  12 +import springfox.documentation.spring.web.plugins.Docket;
  13 +import springfox.documentation.swagger2.annotations.EnableSwagger2;
  14 +
  15 +
  16 +@Configuration
  17 +@EnableSwagger2
  18 +public class SwaggerConfig {
  19 + @Bean
  20 + public Docket createRestApi() {
  21 + return new Docket(DocumentationType.SWAGGER_2)
  22 + .apiInfo(apiInfo())
  23 + .select()
  24 + .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
  25 + .paths(PathSelectors.any())
  26 + .build();
  27 + }
  28 +
  29 + /**
  30 + * 添加摘要信息
  31 + */
  32 + private ApiInfo apiInfo()
  33 + {
  34 + // 用ApiInfoBuilder进行定制
  35 + return new ApiInfoBuilder()
  36 + // 设置标题
  37 + .title("标题:流水鱼plc")
  38 + // 描述
  39 + .description("描述:用于通过mqtt转发流水鱼plc指令控制终端端操作")
  40 + // 作者信息
  41 + .contact(new Contact("", null, null))
  42 + // 版本
  43 + .version("版本号:1.1.1" )
  44 + .build();
  45 + }
  46 +
  47 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.controller;
  2 +
  3 +import com.alibaba.fastjson.JSON;
  4 +import com.google.gson.JsonObject;
  5 +import com.ruoyi.common.utils.DateUtils;
  6 +import com.ruoyi.common.utils.GsonConstructor;
  7 +import com.zhonglai.luhui.device.analysis.comm.factory.Topic;
  8 +import com.zhonglai.luhui.device.analysis.comm.util.ByteUtil;
  9 +import com.zhonglai.luhui.device.analysis.comm.util.StringUtils;
  10 +import com.zhonglai.luhui.device.analysis.comm.util.TableUtil;
  11 +import com.zhonglai.luhui.device.analysis.dto.Message;
  12 +import com.zhonglai.luhui.device.analysis.dto.MessageCode;
  13 +import com.zhonglai.luhui.device.domain.IotDevice;
  14 +import com.zhonglai.luhui.device.domain.IotTerminal;
  15 +import com.zhonglai.luhui.lsy.plc.service.comm.service.DeviceService;
  16 +import com.zhonglai.luhui.lsy.plc.service.comm.service.MqttDeviceService;
  17 +import com.zhonglai.luhui.lsy.plc.service.comm.service.TerminalService;
  18 +import com.zhonglai.luhui.lsy.plc.service.comm.util.TopicUtil;
  19 +import com.zhonglai.luhui.lsy.plc.service.dto.*;
  20 +import com.zhonglai.luhui.lsy.plc.service.service.ClienNoticeService;
  21 +import com.zhonglai.luhui.lsy.plc.service.service.topic.AllPostTopic;
  22 +import io.swagger.annotations.Api;
  23 +import io.swagger.annotations.ApiImplicitParam;
  24 +import io.swagger.annotations.ApiImplicitParams;
  25 +import io.swagger.annotations.ApiOperation;
  26 +import org.eclipse.paho.client.mqttv3.MqttException;
  27 +import org.eclipse.paho.client.mqttv3.MqttMessage;
  28 +import org.slf4j.Logger;
  29 +import org.slf4j.LoggerFactory;
  30 +import org.springframework.beans.factory.annotation.Autowired;
  31 +import org.springframework.web.bind.annotation.*;
  32 +
  33 +import javax.servlet.http.HttpServletResponse;
  34 +import java.util.ArrayList;
  35 +import java.util.HashMap;
  36 +import java.util.List;
  37 +import java.util.Map;
  38 +
  39 +@Api(tags = "设备操作")
  40 +@RestController
  41 +@RequestMapping("/device")
  42 +public class DeviceController {
  43 + private static final Logger log = LoggerFactory.getLogger(DeviceController.class);
  44 +
  45 + @Autowired
  46 + private ClienNoticeService clienNoticeService;
  47 +
  48 + @Autowired
  49 + private DeviceService deviceService;
  50 +
  51 + @ApiOperation("获取一天的日志")
  52 + @ApiImplicitParams({
  53 + @ApiImplicitParam(value = "设备号",name = "deviceId"),
  54 + @ApiImplicitParam(value = "数据",name = "dataObject"),
  55 + @ApiImplicitParam(value = "地址位",name = "addressBits"),
  56 + @ApiImplicitParam(value = "设备表id",name = "deviceInfoId")
  57 + })
  58 + @RequestMapping(value = "write/{deviceInfoId}",method = RequestMethod.POST)
  59 + public Message write(@PathVariable String deviceInfoId, @RequestBody DeviceControlMessage deviceControlMessage)
  60 + {
  61 + log.info("控制指令{}",deviceControlMessage);
  62 +
  63 + Map<String,Object> data = deviceControlMessage.getDataObject();
  64 + if (null == data)
  65 + {
  66 + return new Message(MessageCode.DEFAULT_FAIL_CODE,"没有参数");
  67 + }
  68 + if ( !(data.containsKey("type") && data.get("type").toString().equals("kaiguan")))
  69 + {
  70 + return new Message(MessageCode.DEFAULT_FAIL_CODE,"只支持开关控制");
  71 + }
  72 + DeviceInfo deviceInfo = deviceService.getDeviceInfo(deviceInfoId);
  73 + Topic topic = new Topic("2",deviceInfo.getDevice_type(),deviceControlMessage.getDeviceId(),"PUT",null);
  74 +
  75 + List<DeviceDataConfig> list = DeviceProductProtocol.deviceDataWriteConfigList;
  76 + if(null == list)
  77 + {
  78 + return new Message(MessageCode.DEFAULT_FAIL_CODE,"该设备未配置请联系管理员");
  79 + }
  80 + Map<String,Object> map = new HashMap<>();
  81 + //记录日志
  82 + for (DeviceDataConfig deviceDataConfig:list)
  83 + {
  84 + if(deviceDataConfig.getSensor_numer().equals(deviceControlMessage.getAddressBits()) && deviceDataConfig.getPlc_data_type().sensorDataType.equals("3") )
  85 + {
  86 + //记录日志
  87 + map.put(deviceDataConfig.getAttribute_name(), data.get("value").toString().equals(deviceDataConfig.getAlarmValue())?1:0);
  88 + }
  89 + }
  90 + try {
  91 + MqttMessage mqttMessage = new MqttMessage();
  92 + mqttMessage.setPayload(JSON.toJSONString(map).trim().getBytes());
  93 + Message message = clienNoticeService.sendMessage(topic,mqttMessage);
  94 + if(message.getCode()==1)
  95 + {
  96 + JsonObject rmap = new JsonObject();
  97 + rmap.addProperty("3",data.get("value").toString());
  98 + rmap.addProperty("9","01");
  99 + message.setData(rmap.toString());
  100 + DeviceInfo deviceInfo1 = new DeviceInfo();
  101 + deviceInfo1.setId(deviceInfoId);
  102 +
  103 + JsonObject object = new JsonObject();
  104 + if(StringUtils.isNotEmpty(deviceInfo.getDataValue()))
  105 + {
  106 + object = GsonConstructor.get().fromJson(deviceInfo.getDataValue(),JsonObject.class);
  107 + }
  108 + object.addProperty("3",data.get("value").toString());
  109 + deviceInfo1.setDataValue(object.toString());
  110 + deviceService.upDeviceInfo(deviceInfo1);
  111 + LogDeviceOperation logDeviceOperation = addLogDeviceOperation(topic.getClientid(),deviceControlMessage.getAddressBits(),null,"设备远程"+("01".equals(data.get("value").toString())?"开启":"关闭"),data.get("value").toString(),deviceInfo.getDataValue(),1);
  112 + List<LogDeviceOperation> list1 = new ArrayList<>();
  113 + list1.add(logDeviceOperation);
  114 + deviceService.addloglist(list1,
  115 + TableUtil.getNowTableName("runing_fish_device_operation","log_device_operation",3));
  116 + }
  117 + return message;
  118 + } catch (MqttException e) {
  119 + log.error("指令转发失败",e);
  120 + return new Message(MessageCode.DEFAULT_FAIL_CODE,"指令转发失败");
  121 + } catch (InterruptedException e) {
  122 + log.error("指令转发失败",e);
  123 + return new Message(MessageCode.DEFAULT_FAIL_CODE,"指令转发失败");
  124 + }
  125 +
  126 + }
  127 +
  128 + /**
  129 + * 添加设备操作日志记录
  130 + * @param deviceId 设备imei
  131 + * @param sensorNum 传感器或控制器编号
  132 + * @param operationInstruction 设备操作指令
  133 + * @param describe 设备操作描述
  134 + * @param newState 设备操作后的状态
  135 + * @param isStateChange 是否有状态改变(0否,1是)
  136 + */
  137 + protected LogDeviceOperation addLogDeviceOperation(String deviceId, String sensorNum, String operationInstruction, String describe, String newState, String oldState, Integer isStateChange)
  138 + {
  139 + //更新设备操作日志记录
  140 + LogDeviceOperation logDeviceOperation = new LogDeviceOperation();
  141 + logDeviceOperation.setDeviceId(deviceId);
  142 + logDeviceOperation.setSensorOrController(sensorNum);
  143 + logDeviceOperation.setDeviceOperationTime(DateUtils.getNowTimeMilly());
  144 + logDeviceOperation.setOperationInstruction(operationInstruction);
  145 + logDeviceOperation.setOperationDescribe(describe);
  146 + logDeviceOperation.setDeviceNewState(newState);
  147 + logDeviceOperation.setDeviceOldState(oldState);
  148 + logDeviceOperation.setDeviceOperationType("-1");
  149 + logDeviceOperation.setIsStateChange(isStateChange);
  150 +
  151 + return logDeviceOperation ;
  152 +
  153 + }
  154 +
  155 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.controller;
  2 +
  3 +import com.alibaba.fastjson.JSON;
  4 +import com.alibaba.fastjson.util.IOUtils;
  5 +import com.zhonglai.luhui.device.analysis.comm.util.DateUtils;
  6 +import com.zhonglai.luhui.device.analysis.dto.Message;
  7 +import com.zhonglai.luhui.device.analysis.dto.MessageCode;
  8 +import io.swagger.annotations.Api;
  9 +import io.swagger.annotations.ApiImplicitParam;
  10 +import io.swagger.annotations.ApiImplicitParams;
  11 +import io.swagger.annotations.ApiOperation;
  12 +import org.springframework.stereotype.Controller;
  13 +import org.springframework.web.bind.annotation.PathVariable;
  14 +import org.springframework.web.bind.annotation.RequestMapping;
  15 +import org.springframework.web.bind.annotation.RequestMethod;
  16 +
  17 +import javax.servlet.http.HttpServletResponse;
  18 +import java.io.*;
  19 +import java.util.Date;
  20 +import java.util.zip.ZipEntry;
  21 +import java.util.zip.ZipFile;
  22 +
  23 +@Api(tags = "设备操作")
  24 +@Controller
  25 +@RequestMapping("/log")
  26 +public class LogController {
  27 + @ApiOperation("获取一天的日志")
  28 + @ApiImplicitParams({
  29 + @ApiImplicitParam(value = "时间(格式:20230114)",name = "time"),
  30 + @ApiImplicitParam(value = "设备imei",name = "imei"),
  31 + })
  32 + @RequestMapping(value = "getOneDateLog/{imei}/{time}",method = RequestMethod.GET)
  33 + public void getOneDateLog(HttpServletResponse response, @PathVariable String imei, @PathVariable String time) throws IOException {
  34 + response.setCharacterEncoding("UTF-8");
  35 + response.setHeader("Content-Type","text/html;charset=utf-8");
  36 + PrintWriter printWriter = response.getWriter();
  37 + String dateString = DateUtils.parseDateToStr("yyyyMMdd",new Date());
  38 + String fileName= imei+"_"+time+".log";
  39 + if(dateString.equals(time))
  40 + {
  41 + File logsFile = new File("logs/"+fileName);
  42 + if (!logsFile.exists())
  43 + {
  44 + printWriter.println(JSON.toJSONString(new Message(MessageCode.DEFAULT_FAIL_CODE,"文件"+logsFile.getPath()+"不存在")));
  45 + }
  46 + BufferedReader reader = null;
  47 + try {
  48 + reader = new BufferedReader(new FileReader(logsFile));
  49 + String line;
  50 + while((line = reader.readLine()) != null){
  51 + printWriter.println(line);
  52 + printWriter.println("<br/>");
  53 + }
  54 + } catch (IOException e) {
  55 + e.printStackTrace();
  56 + }finally {
  57 + IOUtils.close(printWriter);
  58 + IOUtils.close(reader);
  59 + }
  60 +
  61 + }
  62 + File logsFile = new File("zip/"+time+".zip");
  63 + BufferedReader reader = null;
  64 + try {
  65 + ZipFile zipFile = new ZipFile(logsFile);
  66 + reader = new BufferedReader(new InputStreamReader(zipFile.getInputStream(new ZipEntry(fileName))));
  67 + String line;
  68 + while((line = reader.readLine()) != null)
  69 + {
  70 + printWriter.println(line);
  71 + printWriter.println("<br/>");
  72 + }
  73 +
  74 + } catch (IOException e) {
  75 + printWriter.println(JSON.toJSONString(new Message(MessageCode.DEFAULT_FAIL_CODE,e.getMessage())));
  76 + }finally {
  77 + IOUtils.close(printWriter);
  78 + IOUtils.close(reader);
  79 + }
  80 + }
  81 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.dto;
  2 +
  3 +import com.alibaba.fastjson.JSONObject;
  4 +import com.zhonglai.luhui.device.analysis.comm.dto.ServerDto;
  5 +
  6 +import java.util.List;
  7 +
  8 +public class AllPostDto extends ServerDto {
  9 +
  10 + private List<DeviceInfo> deviceInfoList;
  11 +
  12 + private JSONObject data;
  13 +
  14 + public JSONObject getData() {
  15 + return data;
  16 + }
  17 +
  18 + public void setData(JSONObject data) {
  19 + this.data = data;
  20 + }
  21 +
  22 + public List<DeviceInfo> getDeviceInfoList() {
  23 + return deviceInfoList;
  24 + }
  25 +
  26 + public void setDeviceInfoList(List<DeviceInfo> deviceInfoList) {
  27 + this.deviceInfoList = deviceInfoList;
  28 + }
  29 +
  30 +
  31 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.dto;
  2 +
  3 +import com.google.gson.JsonObject;
  4 +
  5 +import java.util.Map;
  6 +
  7 +/**
  8 + * plc控制请求消息体
  9 + * Created by zhonglai on 2016/12/30.
  10 + */
  11 +public class DeviceControlMessage {
  12 +
  13 + private String deviceId; //设备号
  14 + private String addressBits; //地址位
  15 + private String commandWord; //命令字
  16 + private Map<String,Object> dataObject; //数据
  17 + private String commandTye ; //指令类型
  18 +
  19 + public String getDeviceId() {
  20 + return deviceId;
  21 + }
  22 +
  23 + public void setDeviceId(String deviceId) {
  24 + this.deviceId = deviceId;
  25 + }
  26 +
  27 + public String getAddressBits() {
  28 + return addressBits;
  29 + }
  30 +
  31 + public void setAddressBits(String addressBits) {
  32 + this.addressBits = addressBits;
  33 + }
  34 +
  35 + public String getCommandWord() {
  36 + return commandWord;
  37 + }
  38 +
  39 + public void setCommandWord(String commandWord) {
  40 + this.commandWord = commandWord;
  41 + }
  42 +
  43 + public Map<String, Object> getDataObject() {
  44 + return dataObject;
  45 + }
  46 +
  47 + public void setDataObject(Map<String, Object> dataObject) {
  48 + this.dataObject = dataObject;
  49 + }
  50 +
  51 + public String getCommandTye() {
  52 + return commandTye;
  53 + }
  54 +
  55 + public void setCommandTye(String commandTye) {
  56 + this.commandTye = commandTye;
  57 + }
  58 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +@Data
  6 +public class DeviceDataConfig {
  7 + private Integer number;
  8 + private String attribute_name;
  9 + private String address_bit;
  10 + private PLCType device_type;
  11 + private String sensor_numer;
  12 + private String attribute_describe;
  13 + private PLCDataType plc_data_type;
  14 +
  15 + private String alarmCode;
  16 + private String alarmValue;
  17 + public DeviceDataConfig()
  18 + {
  19 +
  20 + }
  21 +
  22 + public DeviceDataConfig(Integer number, String attribute_name, String address_bit, PLCType device_type, PLCDataType plc_data_type,String sensor_numer,String attribute_describe) {
  23 + this.number = number;
  24 + this.attribute_name = attribute_name;
  25 + this.address_bit = address_bit;
  26 + this.device_type = device_type;
  27 + this.plc_data_type = plc_data_type;
  28 + this.sensor_numer = sensor_numer;
  29 + this.attribute_describe = attribute_describe;
  30 + }
  31 +
  32 + public DeviceDataConfig(Integer number, String attribute_name, String address_bit, PLCType device_type, PLCDataType plc_data_type,String sensor_numer,String attribute_describe,String alarmCode,String alarmValue) {
  33 + this.number = number;
  34 + this.attribute_name = attribute_name;
  35 + this.address_bit = address_bit;
  36 + this.device_type = device_type;
  37 + this.plc_data_type = plc_data_type;
  38 + this.sensor_numer = sensor_numer;
  39 + this.attribute_describe = attribute_describe;
  40 + this.alarmCode = alarmCode;
  41 + this.alarmValue = alarmValue;
  42 + }
  43 +
  44 + public String getDeviceInfoId(String imei)
  45 + {
  46 + if("00".equals(sensor_numer))
  47 + {
  48 + return imei;
  49 + }
  50 + return imei+"_"+sensor_numer;
  51 + }
  52 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.dto;
  2 +
  3 +
  4 +import lombok.Data;
  5 +
  6 +/**
  7 + * @Author: fuchao
  8 + * @Description :设备信息表
  9 + * @Date: Created in 22:05 2016/12/7
  10 + */
  11 +@Data
  12 +public class DeviceInfo {
  13 +
  14 + private String id; //设备主键ID(设备IMEI号加编号)
  15 + private String dataValue; //数据值(json字符串)
  16 + private String alarmCode; //告警代码(正常-00)
  17 + private String online; //设备在线状态(00-不在线,01-在线)
  18 + private Integer dataUpdateTime; //更新时间
  19 + private String deviceServiceIp; //设备服务器IP
  20 + private String device_type; //设备类型
  21 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.dto;
  2 +
  3 +import lombok.Data;
  4 +
  5 +import java.util.ArrayList;
  6 +import java.util.HashMap;
  7 +import java.util.List;
  8 +import java.util.Map;
  9 +
  10 +/**
  11 + * 产品协议
  12 + */
  13 +public class DeviceProductProtocol {
  14 + public static String payloadtype = "Json";
  15 + public static List<DeviceDataConfig> deviceDataConfigList = new ArrayList<>();
  16 +
  17 + public static List<DeviceDataConfig> deviceDataWriteConfigList = new ArrayList<>();
  18 +
  19 + public static void init()
  20 + {
  21 + deviceDataConfigList.add(new DeviceDataConfig(1,"C001A_RUN","I0.0",PLCType.推水机,PLCDataType.控制器状态码,"01","运行信号"));
  22 + deviceDataConfigList.add(new DeviceDataConfig(2,"C001A_ALARM","I0.1",PLCType.推水机,PLCDataType.故障代码,"01","故障信号","11","01"));
  23 + deviceDataConfigList.add(new DeviceDataConfig(3,"C001B_RUN","I0.2",PLCType.推水机,PLCDataType.控制器状态码,"02","运行信号"));
  24 + deviceDataConfigList.add(new DeviceDataConfig(4,"C001B_ALARM","I0.3",PLCType.推水机,PLCDataType.故障代码,"02","故障信号","11","01"));
  25 + deviceDataConfigList.add(new DeviceDataConfig(5,"C001C_RUN","I0.4",PLCType.推水机,PLCDataType.控制器状态码,"03","运行信号"));
  26 + deviceDataConfigList.add(new DeviceDataConfig(6,"C001C_ALARM","I0.5",PLCType.推水机,PLCDataType.故障代码,"03","故障信号","11","01"));
  27 + deviceDataConfigList.add(new DeviceDataConfig(7,"C002_RUN","I0.6",PLCType.增氧机,PLCDataType.控制器状态码,"34","运行信号"));
  28 + deviceDataConfigList.add(new DeviceDataConfig(8,"C002_ALARM","I0.7",PLCType.增氧机,PLCDataType.故障代码,"34","故障信号","11","01"));
  29 + deviceDataConfigList.add(new DeviceDataConfig(9,"P001A_RUN","I1.0",PLCType.排污,PLCDataType.控制器状态码,"21","运行信号"));
  30 + deviceDataConfigList.add(new DeviceDataConfig(10,"P001A_ALARM","I1.1",PLCType.排污,PLCDataType.故障代码,"21","故障信号","11","01"));
  31 + deviceDataConfigList.add(new DeviceDataConfig(11,"P001B_RUN","I1.2",PLCType.排污,PLCDataType.控制器状态码,"22","运行信号"));
  32 + deviceDataConfigList.add(new DeviceDataConfig(12,"P001B_ALARM","I1.3",PLCType.排污,PLCDataType.故障代码,"22","故障信号","11","01"));
  33 + deviceDataConfigList.add(new DeviceDataConfig(13,"P001C_RUN","I1.4",PLCType.排污,PLCDataType.控制器状态码,"23","运行信号"));
  34 + deviceDataConfigList.add(new DeviceDataConfig(14,"P001C_ALARM","I1.5",PLCType.排污,PLCDataType.控制器状态码,"23","故障信号","11","01"));
  35 + deviceDataConfigList.add(new DeviceDataConfig(15,"SD_RUN","I1.6",null,PLCDataType.故障代码,"00","市电供电信号","12","00"));
  36 + deviceDataConfigList.add(new DeviceDataConfig(16,"FD_RUN","I1.7",null,PLCDataType.故障代码,"00","发电供电信号","13","01"));
  37 + deviceDataConfigList.add(new DeviceDataConfig(17,"DY_ALARM","I2.0",null,PLCDataType.故障代码,"00","电源故障信号","51","01"));
  38 + deviceDataConfigList.add(new DeviceDataConfig(18,"SYS_AUTO","I2.1",null,PLCDataType.控制柜状态,"00","系统自动允许"));
  39 + deviceDataConfigList.add(new DeviceDataConfig(26,"TX_RUN","M0.0",null,PLCDataType.故障代码,"00","远程通讯正常","01","00"));
  40 + deviceDataConfigList.add(new DeviceDataConfig(41,"SYS_ALARM","M1.7",null,PLCDataType.故障代码,"00","设备故障报警","01","01"));
  41 +
  42 + deviceDataWriteConfigList.add(new DeviceDataConfig(27,"YC_ST_C001A","M0.1",PLCType.推水机,PLCDataType.控制器状态码,"01","远程启动按钮",null,"01"));
  43 + deviceDataWriteConfigList.add(new DeviceDataConfig(28,"YC_STP_C001A","M0.2",PLCType.推水机,PLCDataType.控制器状态码,"01","远程停止按钮",null,"00"));
  44 + deviceDataWriteConfigList.add(new DeviceDataConfig(29,"YC_ST_C001B","M0.3",PLCType.推水机,PLCDataType.控制器状态码,"02","远程启动按钮",null,"01"));
  45 + deviceDataWriteConfigList.add(new DeviceDataConfig(30,"YC_STP_C001B","M0.4",PLCType.推水机,PLCDataType.控制器状态码,"02","远程停止按钮",null,"00"));
  46 + deviceDataWriteConfigList.add(new DeviceDataConfig(31,"YC_ST_C001C","M0.5",PLCType.推水机,PLCDataType.控制器状态码,"03","远程启动按钮",null,"01"));
  47 + deviceDataWriteConfigList.add(new DeviceDataConfig(32,"YC_STP_C001C","M0.6",PLCType.推水机,PLCDataType.控制器状态码,"03","远程停止按钮",null,"00"));
  48 + deviceDataWriteConfigList.add(new DeviceDataConfig(33,"YC_ST_C002","M0.7",PLCType.增氧机,PLCDataType.控制器状态码,"34","远程启动按钮",null,"01"));
  49 + deviceDataWriteConfigList.add(new DeviceDataConfig(34,"YC_STP_C002","M1.9",PLCType.增氧机,PLCDataType.控制器状态码,"34","远程停止按钮",null,"00"));
  50 + deviceDataWriteConfigList.add(new DeviceDataConfig(35,"YC_ST_P001A","M1.1",PLCType.排污,PLCDataType.控制器状态码,"21","远程启动按钮",null,"01"));
  51 + deviceDataWriteConfigList.add(new DeviceDataConfig(36,"YC_STP_P001A","M1.2",PLCType.排污,PLCDataType.控制器状态码,"21","远程停止按钮",null,"00"));
  52 + deviceDataWriteConfigList.add(new DeviceDataConfig(37,"YC_ST_P001B","M1.3",PLCType.排污,PLCDataType.控制器状态码,"22","远程启动按钮",null,"01"));
  53 + deviceDataWriteConfigList.add(new DeviceDataConfig(38,"YC_STP_P001B","M1.4",PLCType.排污,PLCDataType.控制器状态码,"22","远程停止按钮",null,"00"));
  54 + deviceDataWriteConfigList.add(new DeviceDataConfig(39,"YC_ST_P001C","M1.5",PLCType.排污,PLCDataType.控制器状态码,"23","远程启动按钮",null,"01"));
  55 + deviceDataWriteConfigList.add(new DeviceDataConfig(40,"YC_STP_P001C","M1.6",PLCType.排污,PLCDataType.控制器状态码,"23","远程停止按钮",null,"00"));
  56 + }
  57 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.dto;
  2 +
  3 +
  4 +/**
  5 + * @Author: fuchao
  6 + * @Description :设备操作日志记录表
  7 + * @Date: Created in 16:57 2016/12/27
  8 + */
  9 +public class LogDeviceOperation {
  10 + private Integer deviceOperationId; //设备操作日志id
  11 + private String deviceId; //设备id
  12 + private Integer deviceOperationTime; //设备操作时间
  13 + private String operationInstruction; //设备操作指令
  14 + private String operationDescribe; //设备操作描述
  15 + private String deviceOldState; //设备操作前状态
  16 + private String deviceNewState; //设备操作后的状态
  17 + private String deviceOperationType; //设备操作类型
  18 + private String sensorOrController; //传感器或控制器编号(控制器以00_开头)
  19 + private Integer isStateChange; //是否有状态改变(0否,1是)
  20 +
  21 + public Integer getDeviceOperationId() {
  22 + return deviceOperationId;
  23 + }
  24 +
  25 + public void setDeviceOperationId(Integer deviceOperationId) {
  26 + this.deviceOperationId = deviceOperationId;
  27 + }
  28 +
  29 + public String getDeviceId() {
  30 + return deviceId;
  31 + }
  32 +
  33 + public void setDeviceId(String deviceId) {
  34 + this.deviceId = deviceId;
  35 + }
  36 +
  37 + public Integer getDeviceOperationTime() {
  38 + return deviceOperationTime;
  39 + }
  40 +
  41 + public void setDeviceOperationTime(Integer deviceOperationTime) {
  42 + this.deviceOperationTime = deviceOperationTime;
  43 + }
  44 +
  45 + public String getOperationInstruction() {
  46 + return operationInstruction;
  47 + }
  48 +
  49 + public void setOperationInstruction(String operationInstruction) {
  50 + this.operationInstruction = operationInstruction;
  51 + }
  52 +
  53 + public String getOperationDescribe() {
  54 + return operationDescribe;
  55 + }
  56 +
  57 + public void setOperationDescribe(String operationDescribe) {
  58 + this.operationDescribe = operationDescribe;
  59 + }
  60 +
  61 + public String getDeviceOldState() {
  62 + return deviceOldState;
  63 + }
  64 +
  65 + public void setDeviceOldState(String deviceOldState) {
  66 + this.deviceOldState = deviceOldState;
  67 + }
  68 +
  69 + public String getDeviceNewState() {
  70 + return deviceNewState;
  71 + }
  72 +
  73 + public void setDeviceNewState(String deviceNewState) {
  74 + this.deviceNewState = deviceNewState;
  75 + }
  76 +
  77 + public String getDeviceOperationType() {
  78 + return deviceOperationType;
  79 + }
  80 +
  81 + public void setDeviceOperationType(String deviceOperationType) {
  82 + this.deviceOperationType = deviceOperationType;
  83 + }
  84 +
  85 + public String getSensorOrController() {
  86 + return sensorOrController;
  87 + }
  88 +
  89 + public void setSensorOrController(String sensorOrController) {
  90 + this.sensorOrController = sensorOrController;
  91 + }
  92 +
  93 + public Integer getIsStateChange() {
  94 + return isStateChange;
  95 + }
  96 +
  97 + public void setIsStateChange(Integer isStateChange) {
  98 + this.isStateChange = isStateChange;
  99 + }
  100 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.dto;
  2 +
  3 +
  4 +/**
  5 + * @Author: fuchao
  6 + * @Description :设备DTU表
  7 + * @Date: Created in 10:26 2016/12/25
  8 + */
  9 +public class OrderDtu {
  10 +
  11 + private Integer orderDtuId; //dtu主键
  12 + private String orderDtuImei; //设备的imei
  13 + private String orderDtuSim; //卡号
  14 + private String deviceType; //设备类型
  15 + private Integer orderDtuCreateTime; //记录时间
  16 + private Integer userLoginId; //登录表主键id(数据级联登录表插入)
  17 + private String userLoginName; //登录名(唯一,数据级联登录表插入)
  18 + private Integer purchaseGoodsId; //采购商品id
  19 + private Integer purchaseId; //采购id
  20 + private String orderDtuSimId; //sim卡id编号
  21 + private Integer orderDtuState; //设备库存状态(0库存,1销售,2售后)
  22 + private Integer orderWorkState; //设备工作状态(0正常,1异常)
  23 +
  24 + public Integer getOrderDtuId() {
  25 + return orderDtuId;
  26 + }
  27 +
  28 + public void setOrderDtuId(Integer orderDtuId) {
  29 + this.orderDtuId = orderDtuId;
  30 + }
  31 +
  32 + public String getOrderDtuImei() {
  33 + return orderDtuImei;
  34 + }
  35 +
  36 + public void setOrderDtuImei(String orderDtuImei) {
  37 + this.orderDtuImei = orderDtuImei;
  38 + }
  39 +
  40 + public String getOrderDtuSim() {
  41 + return orderDtuSim;
  42 + }
  43 +
  44 + public void setOrderDtuSim(String orderDtuSim) {
  45 + this.orderDtuSim = orderDtuSim;
  46 + }
  47 +
  48 + public String getDeviceType() {
  49 + return deviceType;
  50 + }
  51 +
  52 + public void setDeviceType(String deviceType) {
  53 + this.deviceType = deviceType;
  54 + }
  55 +
  56 + public Integer getOrderDtuCreateTime() {
  57 + return orderDtuCreateTime;
  58 + }
  59 +
  60 + public void setOrderDtuCreateTime(Integer orderDtuCreateTime) {
  61 + this.orderDtuCreateTime = orderDtuCreateTime;
  62 + }
  63 +
  64 + public Integer getUserLoginId() {
  65 + return userLoginId;
  66 + }
  67 +
  68 + public void setUserLoginId(Integer userLoginId) {
  69 + this.userLoginId = userLoginId;
  70 + }
  71 +
  72 + public String getUserLoginName() {
  73 + return userLoginName;
  74 + }
  75 +
  76 + public void setUserLoginName(String userLoginName) {
  77 + this.userLoginName = userLoginName;
  78 + }
  79 +
  80 + public Integer getPurchaseGoodsId() {
  81 + return purchaseGoodsId;
  82 + }
  83 +
  84 + public void setPurchaseGoodsId(Integer purchaseGoodsId) {
  85 + this.purchaseGoodsId = purchaseGoodsId;
  86 + }
  87 +
  88 + public Integer getPurchaseId() {
  89 + return purchaseId;
  90 + }
  91 +
  92 + public void setPurchaseId(Integer purchaseId) {
  93 + this.purchaseId = purchaseId;
  94 + }
  95 +
  96 + public String getOrderDtuSimId() {
  97 + return orderDtuSimId;
  98 + }
  99 +
  100 + public void setOrderDtuSimId(String orderDtuSimId) {
  101 + this.orderDtuSimId = orderDtuSimId;
  102 + }
  103 +
  104 + public Integer getOrderDtuState() {
  105 + return orderDtuState;
  106 + }
  107 +
  108 + public void setOrderDtuState(Integer orderDtuState) {
  109 + this.orderDtuState = orderDtuState;
  110 + }
  111 +
  112 + public Integer getOrderWorkState() {
  113 + return orderWorkState;
  114 + }
  115 +
  116 + public void setOrderWorkState(Integer orderWorkState) {
  117 + this.orderWorkState = orderWorkState;
  118 + }
  119 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.dto;
  2 +
  3 +/**
  4 + * 数据类型
  5 + */
  6 +public enum PLCDataType {
  7 + 温度("0"),
  8 + 溶氧("1"),
  9 + 故障代码("2"),
  10 + 控制器状态码("3"),
  11 + 气压("5"),
  12 + 气温("4"),
  13 + 控制器模式("6"),
  14 + 氨氮("7"),
  15 + PH("8"),
  16 + 控制柜状态("9");
  17 + public String sensorDataType;
  18 +
  19 + PLCDataType(String sensorDataType)
  20 + {
  21 + this.sensorDataType = sensorDataType;
  22 + }
  23 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.dto;
  2 +
  3 +public enum PLCType {
  4 + 鱼儿乐(0),
  5 + 喂料机(1),
  6 + 增氧机(2),
  7 + 排污(3),
  8 + 曝气(4),
  9 + 流量计(5),
  10 + 水位计(6),
  11 + 推水机(7),
  12 + 备用(8);
  13 +
  14 + private Integer device_terminal_type_key;
  15 +
  16 + PLCType(Integer device_terminal_type_key)
  17 + {
  18 + this.device_terminal_type_key = device_terminal_type_key;
  19 + }
  20 +
  21 + public Integer getDevice_terminal_type_key() {
  22 + return device_terminal_type_key;
  23 + }
  24 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.dto;
  2 +
  3 +import com.zhonglai.luhui.device.analysis.comm.dto.ServerDto;
  4 +import lombok.Data;
  5 +
  6 +@Data
  7 +public class PutReqDto extends ServerDto {
  8 + private String result;
  9 + private String time;
  10 + private String msg;
  11 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.service;
  2 +
  3 +import com.zhonglai.luhui.device.analysis.comm.clien.ClienConnection;
  4 +import com.zhonglai.luhui.device.analysis.comm.clien.impl.ClienConnectionImpl;
  5 +import com.zhonglai.luhui.device.analysis.comm.dto.ApiClientRePlyDto;
  6 +import com.zhonglai.luhui.device.analysis.comm.dto.TerminalClientRePlyDto;
  7 +import com.zhonglai.luhui.device.analysis.comm.factory.Topic;
  8 +import com.zhonglai.luhui.device.analysis.comm.util.ByteUtil;
  9 +import com.zhonglai.luhui.device.analysis.dto.Message;
  10 +import com.zhonglai.luhui.lsy.plc.service.comm.service.TerminalService;
  11 +import com.zhonglai.luhui.lsy.plc.service.comm.util.TopicUtil;
  12 +import net.jodah.expiringmap.ExpirationListener;
  13 +import net.jodah.expiringmap.ExpirationPolicy;
  14 +import net.jodah.expiringmap.ExpiringMap;
  15 +import org.eclipse.paho.client.mqttv3.MqttException;
  16 +import org.eclipse.paho.client.mqttv3.MqttMessage;
  17 +import org.slf4j.Logger;
  18 +import org.slf4j.LoggerFactory;
  19 +import org.springframework.beans.factory.annotation.Autowired;
  20 +import org.springframework.beans.factory.annotation.Value;
  21 +import org.springframework.stereotype.Service;
  22 +
  23 +import java.util.Map;
  24 +import java.util.concurrent.TimeUnit;
  25 +
  26 +/**
  27 + * 客户端通知服务
  28 + */
  29 +@Service
  30 +public class ClienNoticeService {
  31 + private static final Logger log = LoggerFactory.getLogger(ClienNoticeService.class);
  32 +
  33 + @Autowired
  34 + private TerminalService terminalService;
  35 + @Value("${mqtt.client.operationTime}")
  36 + private long operationTime; //客户端操作时间
  37 +
  38 + // maxSize: 设置最大值,添加第11个entry时,会导致第1个立马过期(即使没到过期时间)
  39 + // expiration:设置每个key有效时间10s, 如果key不设置过期时间,key永久有效。
  40 + // variableExpiration: 允许更新过期时间值,如果不设置variableExpiration,不允许后面更改过期时间,一旦执行更改过期时间操作会抛异常UnsupportedOperationException
  41 + // policy:
  42 + // CREATED: 只在put和replace方法清零过期时间
  43 + // ACCESSED: 在CREATED策略基础上增加, 在还没过期时get方法清零过期时间。
  44 + // 清零过期时间也就是重置过期时间,重新计算过期时间.
  45 + private static ExpiringMap<String, ClienConnection> clienConnectionMap = ExpiringMap.builder().maxSize(20000).expiration(15, TimeUnit.SECONDS)
  46 + .asyncExpirationListener(new ExpirationListener<String, ClienConnection>() {
  47 + @Override
  48 + public void expired(String s, ClienConnection clienConnection) {
  49 + log.info("{} 通道消失了>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",s);
  50 + clienConnection.close();
  51 + }
  52 + })
  53 + .expirationPolicy(ExpirationPolicy.CREATED).build();
  54 +
  55 + @Value("#{${mqtt.top_return_map}}")
  56 + private Map<String,String> top_return_map; //topic返回的对应关系
  57 +
  58 + public Message sendMessage(Topic topic, MqttMessage mqttMessage) throws MqttException, InterruptedException {
  59 + //设置通知渠道
  60 + ClienConnection clienConnection = new ClienConnectionImpl();
  61 + String key = TopicUtil.generateClienKey(topic).replace(topic.getTopicType(),top_return_map.get(topic.getTopicType()));
  62 + log.info("设置通知渠道 {} {}",key,clienConnection);
  63 + clienConnectionMap.put(key,clienConnection);
  64 + sendMessage(TopicUtil.generateSendMessageTopic(topic),mqttMessage);
  65 + synchronized(clienConnection)
  66 + {
  67 + log.info("{}等待通知",topic.getClientid());
  68 + clienConnection.wait(operationTime*1000+3000l);
  69 + }
  70 + //清楚通道
  71 + clienConnectionMap.remove(key);
  72 + log.info("{}收到通知{}",topic.getClientid(),clienConnection.getReplyMessage().getMessage());
  73 + Message message = clienConnection.getReplyMessage();
  74 + log.info("{}返回通知{}",topic.getClientid(),message);
  75 +
  76 + return message;
  77 + }
  78 +
  79 + /**
  80 + * 发送消息
  81 + * @param mqttMessage
  82 + * @throws MqttException
  83 + * @throws InterruptedException
  84 + */
  85 + public void sendMessage(String topic,MqttMessage mqttMessage) throws MqttException, InterruptedException {
  86 + //发生指令,等待通知
  87 + log.info(topic+"发送的消息内容"+ ByteUtil.hexStringToSpace(ByteUtil.toHexString(mqttMessage.getPayload()).toUpperCase())+" 转化为字符串:"+new String(mqttMessage.getPayload()));
  88 + terminalService.publish(topic,mqttMessage);
  89 + }
  90 +
  91 + public ClienConnection getClienConnection(Topic topic)
  92 + {
  93 + return clienConnectionMap.get(TopicUtil.generateClienKey(topic));
  94 + }
  95 +
  96 + /**
  97 + * 通知给api操作端
  98 + * @param topic
  99 + * @param apiClientRePlyDto
  100 + */
  101 + public void replySendMessage(Topic topic, ApiClientRePlyDto apiClientRePlyDto)
  102 + {
  103 + log.info("开始通知{},数据:{}",topic,apiClientRePlyDto);
  104 + //判断有没有需要回复的客户端,如果有就回复
  105 + ClienConnection clienConnection = getClienConnection(topic);
  106 + if(null != clienConnection)
  107 + {
  108 + synchronized(clienConnection)
  109 + {
  110 + log.info("正在通知{},通知结果{}",topic,apiClientRePlyDto);
  111 + clienConnection.reply(apiClientRePlyDto);
  112 + }
  113 + }
  114 + log.info("结束通知{}",topic);
  115 + }
  116 +
  117 + /**
  118 + * 通知给下位机终端
  119 + * @param topic
  120 + * @param terminalClientRePlyDto
  121 + * @throws MqttException
  122 + */
  123 + public void replyTerminalMessage(Topic topic, TerminalClientRePlyDto terminalClientRePlyDto) throws MqttException {
  124 + String tc = terminalClientRePlyDto.getReplyCommdTopic(topic);
  125 + MqttMessage mqttMessage = new MqttMessage();
  126 + mqttMessage.setPayload(terminalClientRePlyDto.getCommd());
  127 + log.info("回复终端{}的消息{}",tc,new String(mqttMessage.getPayload()));
  128 + terminalService.publish(terminalClientRePlyDto.getReplyCommdTopic(topic),mqttMessage);
  129 +
  130 + }
  131 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.service;
  2 +
  3 +import com.zhonglai.luhui.device.analysis.comm.util.DateUtils;
  4 +import org.springframework.context.annotation.Configuration;
  5 +import org.springframework.scheduling.annotation.EnableScheduling;
  6 +import org.springframework.scheduling.annotation.Scheduled;
  7 +
  8 +import java.io.*;
  9 +import java.util.Calendar;
  10 +import java.util.Date;
  11 +import java.util.zip.ZipEntry;
  12 +import java.util.zip.ZipOutputStream;
  13 +
  14 +@Configuration //1.主要用于标记配置类,兼备Component的效果。
  15 +@EnableScheduling // 2.开启定时任务
  16 +public class LogTask {
  17 +
  18 + public static void main(String[] args) {
  19 + LogTask logTask = new LogTask();
  20 + logTask.pack();
  21 + }
  22 +
  23 + //每天凌晨1点钟,打包日志
  24 + @Scheduled(cron = "0 0 1 * * ?")
  25 + private void pack() {
  26 +
  27 + File logsFile = new File("logs/");
  28 + if(logsFile.exists() )
  29 + {
  30 + Calendar cal = Calendar.getInstance();
  31 + cal.setTime(new Date());
  32 + cal.add(Calendar.DATE,-1);
  33 + String dateString = DateUtils.parseDateToStr("yyyyMMdd",cal.getTime());
  34 +
  35 + String logfilename = "_"+ dateString +".log";
  36 +
  37 + String[] files = logsFile.list((dir, name) -> {
  38 + if(name.indexOf(logfilename)>=0)
  39 + {
  40 + return true;
  41 + }
  42 + return false;
  43 + });
  44 +
  45 + if(null != files && files.length != 0 )
  46 + {
  47 + String savePath = "zip/"+dateString+".zip";
  48 + File saveFile = new File(savePath);
  49 + if(!saveFile.getParentFile().exists())
  50 + {
  51 + saveFile.getParentFile().mkdirs();
  52 + }
  53 +
  54 + batchZip(saveFile,logsFile.getPath(),files);
  55 +
  56 + for(String fp:files)
  57 + {
  58 + new File(logsFile.getPath()+"/"+fp).delete();
  59 + }
  60 + }
  61 +
  62 + }
  63 + }
  64 +
  65 + //每天凌晨2点钟,删除30天之前的压缩包
  66 + @Scheduled(cron = "0 0 2 * * ?")
  67 + private void del()
  68 + {
  69 + File logsFile = new File("zip/");
  70 + Calendar cal = Calendar.getInstance();
  71 + cal.setTime(new Date());
  72 + cal.add(Calendar.DATE,-30);
  73 + String dateString = DateUtils.parseDateToStr("yyyyMMdd",cal.getTime());
  74 + String[] files = logsFile.list((dir, name) -> {
  75 +
  76 + if(name.compareTo(dateString)<=0)
  77 + {
  78 + return true;
  79 + }
  80 + return false;
  81 + });
  82 +
  83 + if(null != files && files.length != 0 )
  84 + {
  85 + for(String fp:files)
  86 + {
  87 + new File(logsFile.getPath()+"/"+fp).delete();
  88 + }
  89 + }
  90 + }
  91 + /**
  92 + * 批量压缩
  93 + * @param saveFile 压缩文件保存地址
  94 + * @param files 被压缩文件地址列表
  95 + */
  96 + private void batchZip(File saveFile,String path,String[] files)
  97 + {
  98 + ZipOutputStream zip = null;
  99 + try {
  100 + zip = new ZipOutputStream(new FileOutputStream(saveFile));
  101 + for(String filepath:files)
  102 + {
  103 + zip(zip,path+"/"+filepath);
  104 + }
  105 + zip.finish();
  106 + } catch (IOException e) {
  107 + e.printStackTrace();
  108 + }finally {
  109 + if(null != zip)
  110 + {
  111 + try {
  112 + zip.close();
  113 + } catch (IOException e) {
  114 + e.printStackTrace();
  115 + }
  116 + }
  117 + }
  118 + }
  119 +
  120 +
  121 + /**
  122 + * 压缩
  123 + * @param zip 压缩文件流
  124 + * @param filepath 被压缩文件地址
  125 + * @throws IOException
  126 + */
  127 + private void zip( ZipOutputStream zip,String filepath) throws IOException {
  128 + String[] fss = filepath.split("\\/");
  129 + zip.putNextEntry(new ZipEntry(fss[fss.length-1]));
  130 + //用字节方式读取源文件
  131 + InputStream is = null;
  132 + BufferedInputStream bis = null;
  133 + try {
  134 + is = new FileInputStream(filepath);
  135 + //创建一个缓存区
  136 + bis = new BufferedInputStream(is);
  137 + //字节数组,每次读取1024个字节
  138 + byte[] b = new byte[1024];
  139 + //循环读取,边读边写
  140 + while (bis.read(b) != -1) {
  141 + //写入压缩文件
  142 + zip.write(b);
  143 + }
  144 + } catch (IOException e) {
  145 + e.printStackTrace();
  146 + }finally {
  147 + //关闭流
  148 + if(null != bis)
  149 + {
  150 + bis.close();
  151 + }
  152 + if(null != is)
  153 + {
  154 + is.close();
  155 + }
  156 + }
  157 +
  158 + }
  159 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.service;
  2 +
  3 +import com.ruoyi.common.utils.GsonConstructor;
  4 +import com.zhonglai.luhui.device.analysis.comm.dao.BaseDao;
  5 +import com.zhonglai.luhui.device.analysis.comm.dto.DeviceSensorData;
  6 +import com.zhonglai.luhui.device.analysis.comm.dto.ServerDto;
  7 +import com.zhonglai.luhui.device.analysis.comm.factory.Topic;
  8 +import com.zhonglai.luhui.device.analysis.comm.util.TableUtil;
  9 +import com.zhonglai.luhui.lsy.plc.service.dto.AllPostDto;
  10 +import com.zhonglai.luhui.lsy.plc.service.dto.DeviceInfo;
  11 +import com.zhonglai.luhui.lsy.plc.service.dto.LogDeviceOperation;
  12 +import org.slf4j.Logger;
  13 +import org.slf4j.LoggerFactory;
  14 +import org.springframework.stereotype.Service;
  15 +
  16 +import java.util.ArrayList;
  17 +import java.util.List;
  18 +
  19 +@Service
  20 +public class PLCDataPersistenceService {
  21 + protected BaseDao baseDao = new BaseDao();
  22 +
  23 + private static final Logger log = LoggerFactory.getLogger(PLCDataPersistenceService.class);
  24 + public void persistence(Topic topic, ServerDto serverDto)
  25 + {
  26 + log.info("更新数据{}",topic);
  27 +
  28 + if(serverDto instanceof AllPostDto)
  29 + {
  30 + List<DeviceInfo> list = ((AllPostDto)serverDto).getDeviceInfoList();
  31 + if(null != list && list.size() != 0 )
  32 + {
  33 + for (DeviceInfo deviceInfo:list)
  34 + {
  35 + baseDao.update(deviceInfo);
  36 + }
  37 + }
  38 + }
  39 +
  40 + //曲线数据入库
  41 + List<DeviceSensorData> dsdList = serverDto.getDeviceSensorDataList();
  42 + if(null != dsdList && dsdList.size() != 0)
  43 + {
  44 + baseDao.insertList(dsdList, TableUtil.getNowTableName("runing_fish_data","device_sensor_data",3));
  45 + }
  46 +
  47 + //日志入库
  48 + List<com.zhonglai.luhui.device.analysis.comm.dto.LogDeviceOperation> doList = serverDto.getLogDeviceOperationList();
  49 + if(null != doList && doList.size() != 0)
  50 + {
  51 + List<LogDeviceOperation> loglist = new ArrayList<>();
  52 + for(com.zhonglai.luhui.device.analysis.comm.dto.LogDeviceOperation oldlog:doList)
  53 + {
  54 + LogDeviceOperation newLog = GsonConstructor.get().fromJson(GsonConstructor.get().toJson(oldlog),LogDeviceOperation.class);
  55 + newLog.setDeviceId(oldlog.getDeviceInfoId());
  56 + loglist.add(newLog);
  57 + }
  58 + baseDao.insertList(loglist, TableUtil.getNowTableName("runing_fish_device_operation","log_device_operation",3));
  59 + }
  60 + }
  61 +
  62 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.service.topic;
  2 +
  3 +import com.alibaba.fastjson.JSONObject;
  4 +import com.ruoyi.common.utils.DateUtils;
  5 +import com.ruoyi.common.utils.GsonConstructor;
  6 +import com.ruoyi.common.utils.StringUtils;
  7 +import com.zhonglai.luhui.device.analysis.comm.config.SysParameter;
  8 +import com.zhonglai.luhui.device.analysis.comm.dto.DeviceOperationTypeEnum;
  9 +import com.zhonglai.luhui.device.analysis.comm.dto.DeviceSensorData;
  10 +import com.zhonglai.luhui.device.analysis.comm.dto.ServerDto;
  11 +import com.zhonglai.luhui.device.analysis.comm.dto.business.BusinessDto;
  12 +import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreement;
  13 +import com.zhonglai.luhui.device.analysis.comm.factory.Topic;
  14 +import com.zhonglai.luhui.device.analysis.comm.util.ByteUtil;
  15 +import com.zhonglai.luhui.lsy.plc.service.comm.service.DeviceService;
  16 +import com.zhonglai.luhui.lsy.plc.service.dto.*;
  17 +import org.slf4j.Logger;
  18 +import org.slf4j.LoggerFactory;
  19 +import org.springframework.beans.factory.annotation.Autowired;
  20 +import org.springframework.stereotype.Service;
  21 +
  22 +import java.util.*;
  23 +
  24 +
  25 +/**
  26 + * 全量上报数据,不需要返回
  27 + */
  28 +@Service("ALL_POST")
  29 +public class AllPostTopic implements BusinessAgreement<AllPostDto> {
  30 + private static final Logger log = LoggerFactory.getLogger(AllPostTopic.class);
  31 + @Autowired
  32 + private DeviceService deviceService;
  33 + @Override
  34 + public ServerDto analysis(Topic topic, AllPostDto data) throws Exception {
  35 +
  36 + if(null == data ) //数据和设备都没有不用解析
  37 + {
  38 + return null;
  39 + }
  40 +
  41 + List<DeviceInfo> list = deviceService.getDeviceInfoList(topic.getClientid());
  42 + if(null == list || list.size() == 0)
  43 + {
  44 + log.info("设备列表{}不存在",topic.getClientid());
  45 + return null;
  46 + }
  47 + data.setDeviceInfoList(list);
  48 +
  49 + if( null == data.getData()) //没有数据、但是有设备
  50 + {
  51 + return null;
  52 + }
  53 + List<DeviceInfo> deviceInfoList = data.getDeviceInfoList(); //数据库以添加的设备列表
  54 +
  55 + JSONObject object = data.getData();
  56 + if(null != object && object.size() !=0)
  57 + {
  58 + List<DeviceDataConfig> deviceDataConfigList = DeviceProductProtocol.deviceDataConfigList; //获取点位表配置
  59 + if(null != deviceDataConfigList && deviceDataConfigList.size() !=0)
  60 + {
  61 + for (DeviceInfo deviceInfo:deviceInfoList)
  62 + {
  63 + String newAlrmCode = "00";
  64 + for (DeviceDataConfig deviceDataConfig:deviceDataConfigList)
  65 + {
  66 + String dttribute_name = deviceDataConfig.getAttribute_name();
  67 + if(object.containsKey(dttribute_name) && null != object.get(dttribute_name)) //点位值存在
  68 + {
  69 + String dttribute_value = object.get(dttribute_name).toString();
  70 + String newDataValue= ByteUtil.changerTwoStr(dttribute_value);
  71 +
  72 + String deviceInfoId = deviceDataConfig.getDeviceInfoId(topic.getClientid()); //根据点位协议解析到设备id
  73 + if(deviceInfoId.equals(deviceInfo.getId()) || deviceInfoId.equals(topic.getClientid())) //点位匹配
  74 + {
  75 + switch (deviceDataConfig.getPlc_data_type())
  76 + {
  77 + case 故障代码:
  78 + if(newDataValue.equals(deviceDataConfig.getAlarmValue()))
  79 + {
  80 + newAlrmCode = deviceDataConfig.getAlarmCode();
  81 + }
  82 + break;
  83 + default:
  84 + String dataValue = deviceInfo.getDataValue();
  85 + JSONObject jsonObject = new JSONObject();
  86 +
  87 + if(StringUtils.isNotEmpty(dataValue))
  88 + {
  89 + jsonObject = GsonConstructor.get().fromJson(dataValue,JSONObject.class);
  90 + }
  91 + String odlDataValue = (String) jsonObject.get(deviceDataConfig.getPlc_data_type().sensorDataType);
  92 + if(!newDataValue.equals(odlDataValue))
  93 + {
  94 + jsonObject.put(deviceDataConfig.getPlc_data_type().sensorDataType,newDataValue); //更新数据
  95 + deviceInfo.setDataValue(jsonObject.toJSONString());
  96 +
  97 + String describe = deviceDataConfig.getAttribute_describe()+newDataValue;
  98 + //记录日志
  99 + if(null != deviceDataConfig.getDevice_type())
  100 + {
  101 + describe = deviceDataConfig.getSensor_numer()+deviceDataConfig.getDevice_type().name()+describe;
  102 + }
  103 + data.getLogDeviceOperationList().add(addLogDeviceOperation(topic.getClientid(),deviceDataConfig.getSensor_numer(),null,describe,newDataValue,odlDataValue,1));
  104 + }
  105 + break;
  106 + }
  107 + }
  108 + }
  109 + }
  110 + deviceInfo.setAlarmCode(newAlrmCode);
  111 + deviceInfo.setDataUpdateTime(DateUtils.getNowTimeMilly());
  112 + deviceInfo.setDeviceServiceIp(SysParameter.service_ip);
  113 + deviceInfo.setOnline("01");
  114 + }
  115 + }
  116 + }
  117 + return data;
  118 + }
  119 +
  120 + @Override
  121 + public AllPostDto toData(BusinessDto data) {
  122 + AllPostDto serverDto = new AllPostDto();
  123 + serverDto.setDeviceInfoList(new ArrayList<>());
  124 + serverDto.setDeviceSensorDataList(new ArrayList<>());
  125 + serverDto.setLogDeviceOperationList(new ArrayList<>());
  126 + if(data.getContentData() instanceof JSONObject)
  127 + {
  128 + serverDto.setData((JSONObject) data.getContentData());
  129 + return serverDto;
  130 + }else if(data.getContentData() instanceof byte[])
  131 + {
  132 + serverDto.setData(JSONObject.parseObject(new String((byte[]) data.getContentData())));
  133 + return serverDto;
  134 + }
  135 +
  136 + return null;
  137 + }
  138 +
  139 +
  140 + /**
  141 + * 添加设备操作日志记录
  142 + * @param deviceId 设备imei
  143 + * @param sensorNum 传感器或控制器编号
  144 + * @param operationInstruction 设备操作指令
  145 + * @param describe 设备操作描述
  146 + * @param newState 设备操作后的状态
  147 + * @param isStateChange 是否有状态改变(0否,1是)
  148 + */
  149 + protected com.zhonglai.luhui.device.analysis.comm.dto.LogDeviceOperation addLogDeviceOperation(String deviceId, String sensorNum, String operationInstruction, String describe, String newState, String oldState, Integer isStateChange)
  150 + {
  151 + //更新设备操作日志记录
  152 + com.zhonglai.luhui.device.analysis.comm.dto.LogDeviceOperation logDeviceOperation = new com.zhonglai.luhui.device.analysis.comm.dto.LogDeviceOperation();
  153 + logDeviceOperation.setDeviceInfoId(deviceId);
  154 + logDeviceOperation.setSensorOrController(sensorNum);
  155 + logDeviceOperation.setDeviceOperationTime(DateUtils.getNowTimeMilly());
  156 + logDeviceOperation.setOperationInstruction(operationInstruction);
  157 + logDeviceOperation.setOperationDescribe(describe);
  158 + logDeviceOperation.setDeviceNewState(newState);
  159 + logDeviceOperation.setDeviceOldState(oldState);
  160 + logDeviceOperation.setDeviceOperationType(-1);
  161 + logDeviceOperation.setIsStateChange(isStateChange);
  162 +
  163 + return logDeviceOperation ;
  164 +
  165 + }
  166 +}
  1 +package com.zhonglai.luhui.lsy.plc.service.service.topic;
  2 +
  3 +import com.alibaba.fastjson.JSONObject;
  4 +import com.zhonglai.luhui.device.analysis.comm.dto.ServerDto;
  5 +import com.zhonglai.luhui.device.analysis.comm.dto.business.BusinessDto;
  6 +import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreement;
  7 +import com.zhonglai.luhui.device.analysis.comm.factory.Topic;
  8 +import com.zhonglai.luhui.device.analysis.dto.MessageCode;
  9 +import com.zhonglai.luhui.lsy.plc.service.dto.PutReqDto;
  10 +import com.zhonglai.luhui.lsy.plc.service.service.ClienNoticeService;
  11 +import org.springframework.beans.factory.annotation.Autowired;
  12 +import org.springframework.stereotype.Service;
  13 +
  14 +/**
  15 + * 更新数据的执行结果
  16 + */
  17 +@Service("PUT_REQ")
  18 +public class PutReqTopic implements BusinessAgreement<PutReqDto> {
  19 + @Autowired
  20 + private ClienNoticeService clienNoticeService; //客户端通知服务
  21 +
  22 + @Override
  23 + public ServerDto analysis(Topic topic, PutReqDto data) throws Exception {
  24 + clienNoticeService.replySendMessage(topic, message -> {
  25 + message.setData(data.getTime());
  26 + message.setCode(MessageCode.DEFAULT_FAIL_CODE);
  27 + message.setMessage(data.getMsg());
  28 + switch (data.getResult())
  29 + {
  30 + case "1":
  31 + message.setCode(MessageCode.DEFAULT_SUCCESS_CODE);
  32 + message.setMessage("成功");
  33 + break;
  34 + }
  35 + });
  36 + return null;
  37 + }
  38 +
  39 + @Override
  40 + public PutReqDto toData(BusinessDto data) {
  41 + PutReqDto putReqDto = JSONObject.parseObject(((JSONObject) data.getContentData()).toJSONString(),PutReqDto.class);
  42 + return putReqDto;
  43 + }
  44 +}
  1 +##服务器配置
  2 +server:
  3 + tomcat:
  4 + uri-encoding: UTF-8
  5 + port: 4883
  6 + servlet:
  7 + context-path: /
  8 +
  9 +spring:
  10 + messages:
  11 + encoding: UTF-8
  12 + mvc:
  13 + #出现错误时, 直接抛出异常
  14 + throw-exception-if-no-handler-found: true
  15 + jackson:
  16 + date-format: yyyy-MM-dd HH:mm:ss
  17 + time-zone: GMT+8
  18 + default-property-inclusion: non_null
  19 +
  20 +mqtt:
  21 + #链接地址
  22 + broker: tcp://47.112.163.61:1883
  23 + #唯一标识
  24 + clientId: ${random.uuid}
  25 + #公司id
  26 + roleid: 2
  27 + mqtt_usernames: PLC_004
  28 + #订阅的topic
  29 + topics: ALL_POST,PUT_REQ
  30 + sub_clientid: '#'
  31 + topicconfig: "/{{roleid}}/{{username}}/{{topicType}}/{{clientid}}"
  32 + top_return_map: '{"PUT":"PUT_REQ"}'
  33 + username: sysuser
  34 + password: "!@#1qaz"
  35 + client:
  36 + #客户端操作时间
  37 + operationTime: 10
  38 +
  39 +sys:
  40 + redis:
  41 + field: "lh:mqttservice:"
  42 + isText: false
  1 +driverClassName=com.mysql.cj.jdbc.Driver
  2 +#url=jdbc:mysql://rm-wz9740un21f09iokuao.mysql.rds.aliyuncs.com:3306/mqtt_broker?useUnicode=true&characterEncoding=utf8&autoReconnect=true
  3 +#username=luhui
  4 +#password=Luhui586
  5 +url=jdbc:mysql://rm-wz9446bn79p0r80ew0o.mysql.rds.aliyuncs.com:3306/runing_fish?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai
  6 +username=luhui
  7 +password=Luhui586
  8 +#\u6700\u5927\u8FDE\u63A5\u6570\u91CF
  9 +maxActive=100
  10 +#\u6700\u5927\u7A7A\u95F2\u8FDE\u63A5
  11 +maxIdle=-1
  12 +#\u6700\u5C0F\u7A7A\u95F2\u8FDE\u63A5
  13 +minIdle=10
  14 +#\u8D85\u65F6\u7B49\u5F85\u65F6\u95F4\u4EE5\u6BEB\u79D2\u4E3A\u5355\u4F4D 60000\u6BEB\u79D2/1000\u7B49\u4E8E60\u79D2
  15 +maxWait=60000
  16 +#removeAbandoned: \u662F\u5426\u81EA\u52A8\u56DE\u6536\u8D85\u65F6\u8FDE\u63A5
  17 +removeAbandoned=true
  18 +#removeAbandonedTimeout: \u8D85\u65F6\u65F6\u95F4(\u4EE5\u79D2\u6570\u4E3A\u5355\u4F4D)
  19 +removeAbandonedTimeout=120
  20 +testOnBorrow=false
  21 +logAbandoned=true
  1 +<configuration>
  2 +<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
  3 + <file>logs/output.log</file>
  4 + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  5 + <fileNamePattern>logs/output.%d{yyyy-MM-dd}.log</fileNamePattern>
  6 + <maxHistory>5</maxHistory>
  7 + </rollingPolicy>
  8 + <encoder>
  9 + <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
  10 + </encoder>
  11 +</appender>
  12 +
  13 +<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
  14 + <encoder>
  15 + <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
  16 + </encoder>
  17 +</appender>
  18 +
  19 +<root level="info">
  20 + <appender-ref ref="FILE" />
  21 + <appender-ref ref="CONSOLE" />
  22 +</root>
  23 +</configuration>
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +
  3 +<assembly>
  4 + <id>bin</id>
  5 + <!-- 最终打包成一个用于发布的zip文件 -->
  6 + <formats>
  7 + <format>zip</format>
  8 + </formats>
  9 +
  10 + <!-- Adds dependencies to zip package under lib directory -->
  11 + <dependencySets>
  12 + <dependencySet>
  13 + <!--
  14 + 不使用项目的artifact,第三方jar不要解压,打包进zip文件的lib目录
  15 + -->
  16 + <useProjectArtifact>false</useProjectArtifact>
  17 + <outputDirectory>lib</outputDirectory>
  18 + <unpack>false</unpack>
  19 + </dependencySet>
  20 + </dependencySets>
  21 +
  22 + <fileSets>
  23 + <!-- 把项目相关的说明文件,打包进zip文件的根目录 -->
  24 + <fileSet>
  25 + <directory>${project.basedir}</directory>
  26 + <outputDirectory>/</outputDirectory>
  27 + <includes>
  28 + <include>README*</include>
  29 + <include>LICENSE*</include>
  30 + <include>NOTICE*</include>
  31 + </includes>
  32 + </fileSet>
  33 +
  34 + <!-- 把项目的配置文件,打包进zip文件的config目录 -->
  35 + <fileSet>
  36 + <directory>${project.basedir}\src\main\resources\configs</directory>
  37 + <outputDirectory>../configs</outputDirectory>
  38 + <includes>
  39 + <include>*.properties</include>
  40 + </includes>
  41 + </fileSet>
  42 +
  43 + <!-- 把项目的配置文件,提出来 -->
  44 + <fileSet>
  45 + <directory>${project.basedir}\src\main\resources</directory>
  46 + <outputDirectory>/</outputDirectory>
  47 + <includes>
  48 + <include>*.properties</include>
  49 + <include>*.yml</include>
  50 + </includes>
  51 + </fileSet>
  52 +
  53 + <!-- 把项目的脚本文件目录( src/main/scripts )中的启动脚本文件,打包进zip文件的跟目录 -->
  54 + <fileSet>
  55 + <directory>${project.basedir}\bin</directory>
  56 + <outputDirectory></outputDirectory>
  57 + <includes>
  58 + <include>start.*</include>
  59 + <include>stop.*</include>
  60 + </includes>
  61 + </fileSet>
  62 +
  63 + <!-- 把项目自己编译出来的jar文件,打包进zip文件的根目录 -->
  64 + <fileSet>
  65 + <directory>${project.build.directory}</directory>
  66 + <outputDirectory></outputDirectory>
  67 + <includes>
  68 + <include>*.jar</include>
  69 + </includes>
  70 + </fileSet>
  71 + </fileSets>
  72 +</assembly>
@@ -49,7 +49,7 @@ mqtt: @@ -49,7 +49,7 @@ mqtt:
49 mqtt_usernames: 6_WP,12_BPQ,10_TLJ,NWDB_2023,WLJ_1,YWB_A700E,12_ZNZY 49 mqtt_usernames: 6_WP,12_BPQ,10_TLJ,NWDB_2023,WLJ_1,YWB_A700E,12_ZNZY
50 #订阅的topic 50 #订阅的topic
51 topics: ADD_POST,ALL_POST,DB_TOPIC_DISTRIBUTE,GET/+,online,PUT_REQ/+,READ_REQ/+ 51 topics: ADD_POST,ALL_POST,DB_TOPIC_DISTRIBUTE,GET/+,online,PUT_REQ/+,READ_REQ/+
52 - sub_clientid: '866838067733465' 52 + sub_clientid: '866520063012785'
53 topicconfig: "/{{roleid}}/{{username}}/{{clientid}}/{{payloadtype}}/{{topicType}}/{{messageid}}" 53 topicconfig: "/{{roleid}}/{{username}}/{{clientid}}/{{payloadtype}}/{{topicType}}/{{messageid}}"
54 top_return_map: '{"PUT":"PUT_REQ","READ":"READ_REQ"}' 54 top_return_map: '{"PUT":"PUT_REQ","READ":"READ_REQ"}'
55 username: sysuser 55 username: sysuser
@@ -3,6 +3,7 @@ package com.zhonglai.luhui.smart.feeder; @@ -3,6 +3,7 @@ package com.zhonglai.luhui.smart.feeder;
3 import com.zhonglai.luhui.smart.feeder.config.OpenCVConfig; 3 import com.zhonglai.luhui.smart.feeder.config.OpenCVConfig;
4 4
5 import com.zhonglai.luhui.smart.feeder.service.InitService; 5 import com.zhonglai.luhui.smart.feeder.service.InitService;
  6 +import org.bytedeco.javacv.FFmpegFrameGrabber;
6 import org.slf4j.Logger; 7 import org.slf4j.Logger;
7 import org.slf4j.LoggerFactory; 8 import org.slf4j.LoggerFactory;
8 9
@@ -12,7 +13,6 @@ public class Main { @@ -12,7 +13,6 @@ public class Main {
12 public static void main(String[] args) { 13 public static void main(String[] args) {
13 logger.info("开始启动服务器"); 14 logger.info("开始启动服务器");
14 OpenCVConfig.loadOpenCv(args); 15 OpenCVConfig.loadOpenCv(args);
15 -  
16 //配置参数 16 //配置参数
17 logger.info("配置参数"); 17 logger.info("配置参数");
18 InitService.initConfig(); 18 InitService.initConfig();
@@ -14,22 +14,22 @@ import java.util.List; @@ -14,22 +14,22 @@ import java.util.List;
14 public class CameraData { 14 public class CameraData {
15 15
16 /** 16 /**
17 - * 当前画面的亮度 17 + * 当前画面的平均亮度
18 */ 18 */
19 private Double brightness; 19 private Double brightness;
20 20
21 /** 21 /**
22 - * 当前画面的反光 22 + * 当前画面的平均反光
23 */ 23 */
24 private Double reflection; 24 private Double reflection;
25 25
26 /** 26 /**
27 - * 当前画面的透明度 27 + * 当前画面的平均透明度
28 */ 28 */
29 private Double transparencyMeasure; 29 private Double transparencyMeasure;
30 30
31 /** 31 /**
32 - * 当前画面的面积 32 + * 当前画面的平均面积
33 */ 33 */
34 private Double area; 34 private Double area;
35 35
@@ -16,8 +16,11 @@ public class FeederCommd10Request implements FeederCommd { @@ -16,8 +16,11 @@ public class FeederCommd10Request implements FeederCommd {
16 { 16 {
17 start_char = new Long(ByteUtil.bytesToLongDESC(data,0,2)).intValue(); 17 start_char = new Long(ByteUtil.bytesToLongDESC(data,0,2)).intValue();
18 register_number = new Long(ByteUtil.bytesToLongDESC(data,2,2)).intValue(); 18 register_number = new Long(ByteUtil.bytesToLongDESC(data,2,2)).intValue();
19 - byte_lenth = new Long(ByteUtil.bytesToLongDESC(data,4,2)).intValue();  
20 - data = ArrayUtils.subarray(data,6,6+byte_lenth); 19 + if (data.length>4)
  20 + {
  21 + byte_lenth = new Long(ByteUtil.bytesToLongDESC(data,4,2)).intValue();
  22 + data = ArrayUtils.subarray(data,6,6+byte_lenth);
  23 + }
21 } 24 }
22 25
23 public Integer getStart_char() { 26 public Integer getStart_char() {
@@ -33,7 +33,7 @@ public class FeederCommdDto extends ModbusDto { @@ -33,7 +33,7 @@ public class FeederCommdDto extends ModbusDto {
33 { 33 {
34 byte[] start_bytes = ByteUtil.intToBytesDESC(feederCommd10Response.getStart_char(),2); 34 byte[] start_bytes = ByteUtil.intToBytesDESC(feederCommd10Response.getStart_char(),2);
35 byte[] number_bytes = ByteUtil.intToBytesDESC( feederCommd10Response.getRegister_number(),2); 35 byte[] number_bytes = ByteUtil.intToBytesDESC( feederCommd10Response.getRegister_number(),2);
36 - byte[] lenth_bytes = ByteUtil.intToBytesDESC( feederCommd10Response.getByte_lenth(),2); 36 + byte[] lenth_bytes = ByteUtil.intToBytesDESC( feederCommd10Response.getByte_lenth(),1);
37 byte[] data = feederCommd10Response.getData(); 37 byte[] data = feederCommd10Response.getData();
38 super.toModbusDto(0x01,0x10, ArrayUtil.addAll(start_bytes,number_bytes,lenth_bytes,data)); 38 super.toModbusDto(0x01,0x10, ArrayUtil.addAll(start_bytes,number_bytes,lenth_bytes,data));
39 this.feederCommd = feederCommd10Response; 39 this.feederCommd = feederCommd10Response;
@@ -15,30 +15,30 @@ public class FeederTimer { @@ -15,30 +15,30 @@ public class FeederTimer {
15 15
16 public void setObjectValue(String field,long value) 16 public void setObjectValue(String field,long value)
17 { 17 {
18 - switch (field) 18 + switch (field.substring(field.indexOf("_")+1))
19 { 19 {
20 - case "timer_start_m": 20 + case "start_m":
21 timer_start_m = Integer.valueOf(Long.toString(value)); 21 timer_start_m = Integer.valueOf(Long.toString(value));
22 break; 22 break;
23 - case "timer_start_h": 23 + case "start_h":
24 timer_start_h =Integer.valueOf(Long.toString(value)); 24 timer_start_h =Integer.valueOf(Long.toString(value));
25 break; 25 break;
26 - case "timer_if_start": 26 + case "if_start":
27 timer_if_start =Integer.valueOf(Long.toString(value)); 27 timer_if_start =Integer.valueOf(Long.toString(value));
28 break; 28 break;
29 - case "timer_is_start": 29 + case "is_start":
30 timer_is_start =Integer.valueOf(Long.toString(value)); 30 timer_is_start =Integer.valueOf(Long.toString(value));
31 break; 31 break;
32 - case "timer_close_m": 32 + case "close_m":
33 timer_close_m =Integer.valueOf(Long.toString(value)); 33 timer_close_m =Integer.valueOf(Long.toString(value));
34 break; 34 break;
35 - case "timer_close_h": 35 + case "close_h":
36 timer_close_h =Integer.valueOf(Long.toString(value)); 36 timer_close_h =Integer.valueOf(Long.toString(value));
37 break; 37 break;
38 - case "timer_if_close": 38 + case "if_close":
39 timer_if_close =Integer.valueOf(Long.toString(value)); 39 timer_if_close =Integer.valueOf(Long.toString(value));
40 break; 40 break;
41 - case "timer_is_close": 41 + case "is_close":
42 timer_is_close =Integer.valueOf(Long.toString(value)); 42 timer_is_close =Integer.valueOf(Long.toString(value));
43 break; 43 break;
44 } 44 }
@@ -13,5 +13,4 @@ public class Condata @@ -13,5 +13,4 @@ public class Condata
13 private Integer interval; //时间间隔 1-18秒 13 private Integer interval; //时间间隔 1-18秒
14 private Integer runstate; //运行状态 1运行、3停止(平台可以设置0启动中,2关闭中,4异常) 14 private Integer runstate; //运行状态 1运行、3停止(平台可以设置0启动中,2关闭中,4异常)
15 private Integer stopfeedcnt; //手动投料倒计时时间 单位分 15 private Integer stopfeedcnt; //手动投料倒计时时间 单位分
16 - private Integer onoff; //运行状态 1运行、3停止(平台可以设置0启动中,2关闭中,4异常)  
17 } 16 }
@@ -90,7 +90,10 @@ public class FishGroupImageRecognitionService { @@ -90,7 +90,10 @@ public class FishGroupImageRecognitionService {
90 90
91 public void stop() 91 public void stop()
92 { 92 {
  93 + srsService.stop();
93 OperatingData.cameraData.setFishGroupImageRecognIsRun(false); 94 OperatingData.cameraData.setFishGroupImageRecognIsRun(false);
  95 + backgroundSubtractor.clear();
  96 +
94 scheduledFuture.cancel(true); 97 scheduledFuture.cancel(true);
95 while (!scheduledFuture.isCancelled()) 98 while (!scheduledFuture.isCancelled())
96 { 99 {
@@ -126,7 +129,7 @@ public class FishGroupImageRecognitionService { @@ -126,7 +129,7 @@ public class FishGroupImageRecognitionService {
126 { 129 {
127 isread = true; 130 isread = true;
128 } 131 }
129 - logger.info("逐帧处理视频,开始处理的判断参数:鱼群图像识别是否开启 {}、摄像头是否可读取 {}",OperatingData.cameraConfig.getFishGroupImageRecognition(),isread); 132 +// logger.info("逐帧处理视频,开始处理的判断参数:鱼群图像识别是否开启 {}、摄像头是否可读取 {}",OperatingData.cameraConfig.getFishGroupImageRecognition(),isread);
130 if(!isread ) 133 if(!isread )
131 { 134 {
132 logger.info("摄像头不可读取"); 135 logger.info("摄像头不可读取");
@@ -286,6 +289,8 @@ public class FishGroupImageRecognitionService { @@ -286,6 +289,8 @@ public class FishGroupImageRecognitionService {
286 } 289 }
287 } 290 }
288 291
  292 + logger.info("当前画面的亮度:{},当前画面的反光:{},当前画面的透明度:{},当前画面的平均面积:{},鱼群规模:{},鱼群数量:{}",brightness,reflection,transparencyMeasure,area,fishSchoolSize, OperatingData.cameraData.getSize());
  293 +
289 } 294 }
290 } 295 }
291 } 296 }
@@ -100,6 +100,8 @@ public class ScaleStepMethodService { @@ -100,6 +100,8 @@ public class ScaleStepMethodService {
100 stringBuffer.append(OperatingData.cameraData.getScaleAreaSumMax()); 100 stringBuffer.append(OperatingData.cameraData.getScaleAreaSumMax());
101 InitService.dateListenService.reportIntelligentFeeding(stringBuffer.toString()); 101 InitService.dateListenService.reportIntelligentFeeding(stringBuffer.toString());
102 } 102 }
  103 +
  104 + System.out.println("尺度之内的面积之和:"+sum+";尺度之内的面积之和曲线的峰值:"+OperatingData.cameraData.getScaleAreaSumMax()+";尺度之内的面积之和占比:"+scaleAreaSumPercentage);
103 },0, OperatingData.cameraConfig.getScaleStep(), TimeUnit.SECONDS); 105 },0, OperatingData.cameraConfig.getScaleStep(), TimeUnit.SECONDS);
104 } 106 }
105 107
@@ -113,7 +113,7 @@ public class SrsService { @@ -113,7 +113,7 @@ public class SrsService {
113 } 113 }
114 } 114 }
115 115
116 - public void close() 116 + private void close()
117 { 117 {
118 if(null != recorder) 118 if(null != recorder)
119 { 119 {
@@ -10,6 +10,7 @@ import com.zhonglai.luhui.smart.feeder.dto.ModbusDto; @@ -10,6 +10,7 @@ import com.zhonglai.luhui.smart.feeder.dto.ModbusDto;
10 import com.zhonglai.luhui.smart.feeder.dto.SerialPortConfig; 10 import com.zhonglai.luhui.smart.feeder.dto.SerialPortConfig;
11 import com.zhonglai.luhui.smart.feeder.dto.commd.FeederCommdDto; 11 import com.zhonglai.luhui.smart.feeder.dto.commd.FeederCommdDto;
12 import com.zhonglai.luhui.smart.feeder.service.ConfigurationParameterService; 12 import com.zhonglai.luhui.smart.feeder.service.ConfigurationParameterService;
  13 +import com.zhonglai.luhui.smart.feeder.service.InitService;
13 import org.slf4j.Logger; 14 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory; 15 import org.slf4j.LoggerFactory;
15 import org.springframework.beans.factory.annotation.Autowired; 16 import org.springframework.beans.factory.annotation.Autowired;
@@ -119,7 +120,9 @@ public class SerialPortService { @@ -119,7 +120,9 @@ public class SerialPortService {
119 120
120 try { 121 try {
121 Thread.sleep(500); 122 Thread.sleep(500);
122 - FeederCommdDto commdDto = new FeederCommdDto(readFromPort(port)); 123 + byte[] bytes = readFromPort(port);
  124 + logger.info("串口返回数据:"+ByteUtil.toHexString(bytes));
  125 + FeederCommdDto commdDto = new FeederCommdDto(bytes);
123 dataQueue.offer(commdDto); // 将数据添加到队列中// 处理串口返回的数据 126 dataQueue.offer(commdDto); // 将数据添加到队列中// 处理串口返回的数据
124 } catch (Exception e) { 127 } catch (Exception e) {
125 logger.error("返回数据处理异常",e); 128 logger.error("返回数据处理异常",e);
@@ -147,18 +150,19 @@ public class SerialPortService { @@ -147,18 +150,19 @@ public class SerialPortService {
147 * @throws IOException 150 * @throws IOException
148 */ 151 */
149 public ModbusDto sendHexData(String hexStr) { 152 public ModbusDto sendHexData(String hexStr) {
  153 + logger.info("串口写入:{}",hexStr);
150 byte[] bytes = ByteUtil.hexStringToByte(hexStr.replace(" ","").trim().toUpperCase()); 154 byte[] bytes = ByteUtil.hexStringToByte(hexStr.replace(" ","").trim().toUpperCase());
151 return sendByte(bytes); 155 return sendByte(bytes);
152 } 156 }
153 157
154 - /**  
155 - * 发送支持中文的字符串  
156 - * @param str  
157 - * @throws IOException  
158 - */  
159 - public ModbusDto sendStrData(String str) {  
160 - return sendByte(str.getBytes(StandardCharsets.UTF_8));  
161 - } 158 +// /**
  159 +// * 发送支持中文的字符串
  160 +// * @param str
  161 +// * @throws IOException
  162 +// */
  163 +// public ModbusDto sendStrData(String str) {
  164 +// return sendByte(str.getBytes(StandardCharsets.UTF_8));
  165 +// }
162 166
163 /** 167 /**
164 * 发送byte数组 168 * 发送byte数组
@@ -221,5 +225,4 @@ public class SerialPortService { @@ -221,5 +225,4 @@ public class SerialPortService {
221 225
222 } 226 }
223 227
224 -  
225 } 228 }
@@ -5,6 +5,7 @@ import com.ruoyi.common.utils.StringUtils; @@ -5,6 +5,7 @@ import com.ruoyi.common.utils.StringUtils;
5 import com.zhonglai.luhui.smart.feeder.config.OperatingData; 5 import com.zhonglai.luhui.smart.feeder.config.OperatingData;
6 import com.zhonglai.luhui.smart.feeder.dto.HCCameraRepose; 6 import com.zhonglai.luhui.smart.feeder.dto.HCCameraRepose;
7 import com.zhonglai.luhui.smart.feeder.service.ConfigurationParameterService; 7 import com.zhonglai.luhui.smart.feeder.service.ConfigurationParameterService;
  8 +import com.zhonglai.luhui.smart.feeder.service.InitService;
8 import com.zhonglai.luhui.smart.feeder.service.PushVideo; 9 import com.zhonglai.luhui.smart.feeder.service.PushVideo;
9 import com.zhonglai.luhui.smart.feeder.service.device.CameraHandle; 10 import com.zhonglai.luhui.smart.feeder.service.device.CameraHandle;
10 import org.bytedeco.ffmpeg.global.avutil; 11 import org.bytedeco.ffmpeg.global.avutil;
@@ -80,6 +81,22 @@ public class CameraRtspHandle implements CameraHandle { @@ -80,6 +81,22 @@ public class CameraRtspHandle implements CameraHandle {
80 while (isOpen() && !isclose) { 81 while (isOpen() && !isclose) {
81 try { 82 try {
82 mat = getMat(); 83 mat = getMat();
  84 + int i=0;
  85 + while (null == mat && i<3)
  86 + {
  87 + logger.info("读取不到视频等待3秒,尝试第"+i+"次");
  88 + Thread.sleep(3000);
  89 + mat = getMat();
  90 + i++;
  91 + }
  92 + if(null == mat)
  93 + {
  94 + InitService.fishGroupImageRecognitionService.stop();
  95 + close();
  96 +
  97 + Thread thread1 = new Thread(() -> init());
  98 + thread1.start();
  99 + }
83 } catch (Exception e) { 100 } catch (Exception e) {
84 logger.error("抓取摄像头帧失败",e); 101 logger.error("抓取摄像头帧失败",e);
85 } 102 }
@@ -27,6 +27,7 @@ @@ -27,6 +27,7 @@
27 <module>lh-server-ops</module> 27 <module>lh-server-ops</module>
28 <module>lh-http-service</module> 28 <module>lh-http-service</module>
29 <module>lh-data-file-service</module> 29 <module>lh-data-file-service</module>
  30 + <module>lh-lsy-plc-service</module>
30 </modules> 31 </modules>
31 32
32 <properties> 33 <properties>