rev:mqtt
This commit is contained in:
Binary file not shown.
@@ -32,6 +32,11 @@ public class OpcDto implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private String opc_host;
|
private String opc_host;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MQTT订阅主题 需要与OPCServer保持一致
|
||||||
|
*/
|
||||||
|
private String topic;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户名
|
* 用户名
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ package org.nl.acs.device.service.impl;
|
|||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.util.IdUtil;
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -85,6 +86,9 @@ public class OpcServiceImpl implements OpcService {
|
|||||||
public List<OpcDto> queryAll(Map whereJson) {
|
public List<OpcDto> queryAll(Map whereJson) {
|
||||||
WQLObject wo = WQLObject.getWQLObject("acs_opc");
|
WQLObject wo = WQLObject.getWQLObject("acs_opc");
|
||||||
JSONArray arr = wo.query().getResultJSONArray(0);
|
JSONArray arr = wo.query().getResultJSONArray(0);
|
||||||
|
if (ObjectUtil.isEmpty(arr)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
List<OpcDto> list = arr.toJavaList(OpcDto.class);
|
List<OpcDto> list = arr.toJavaList(OpcDto.class);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@@ -119,7 +123,7 @@ public class OpcServiceImpl implements OpcService {
|
|||||||
dto.setCreate_time(now);
|
dto.setCreate_time(now);
|
||||||
|
|
||||||
WQLObject wo = WQLObject.getWQLObject("acs_opc");
|
WQLObject wo = WQLObject.getWQLObject("acs_opc");
|
||||||
JSONObject json = (JSONObject) JSONObject.toJSON(dto);
|
JSONObject json = (JSONObject) JSONObject.toJSON(dto);
|
||||||
|
|
||||||
wo.insert(json);
|
wo.insert(json);
|
||||||
}
|
}
|
||||||
@@ -136,7 +140,7 @@ public class OpcServiceImpl implements OpcService {
|
|||||||
dto.setUpdate_by(currentUsername);
|
dto.setUpdate_by(currentUsername);
|
||||||
|
|
||||||
WQLObject wo = WQLObject.getWQLObject("acs_opc");
|
WQLObject wo = WQLObject.getWQLObject("acs_opc");
|
||||||
JSONObject json = (JSONObject) JSONObject.toJSON(dto);
|
JSONObject json = (JSONObject) JSONObject.toJSON(dto);
|
||||||
|
|
||||||
wo.update(json);
|
wo.update(json);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import org.nl.acs.opc.Device;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface DeviceDriver {
|
public interface DeviceDriver {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
default String getDeviceCode() {
|
default String getDeviceCode() {
|
||||||
return this.getDevice().getDevice_code();
|
return this.getDevice().getDevice_code();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public class DeviceExecuteAutoRun extends AbstractAutoRunnable {
|
|||||||
for (int i = 0; !OpcStartTag.is_run; ++i) {
|
for (int i = 0; !OpcStartTag.is_run; ++i) {
|
||||||
log.info("设备执行线程等待opc同步线程...");
|
log.info("设备执行线程等待opc同步线程...");
|
||||||
Thread.sleep(1000L);
|
Thread.sleep(1000L);
|
||||||
if (i > 60) {
|
if (i > 20) {
|
||||||
log.info("设备执行线程放弃等待opc同步线程...");
|
log.info("设备执行线程放弃等待opc同步线程...");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ public class DeviceOpcProtocolRunable implements Runnable, DataCallback, ServerC
|
|||||||
if (OpcConfig.opc_item_read_using_callback) {
|
if (OpcConfig.opc_item_read_using_callback) {
|
||||||
this.runNew();
|
this.runNew();
|
||||||
} else {
|
} else {
|
||||||
this.runOld();
|
//this.runOld();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -590,42 +590,43 @@ public class TaskServiceImpl implements TaskService, ApplicationAutoInitial {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createInst(String ids) throws Exception {
|
public void createInst(String ids) throws Exception {
|
||||||
TaskDto acsTask = this.findById(ids);
|
throw new BadRequestException("创建指令失败!");
|
||||||
if (acsTask == null) throw new BadRequestException("被删除或无权限,操作失败!");
|
// TaskDto acsTask = this.findById(ids);
|
||||||
List<TaskDto> tasksByLinkNum = this.findByLinkNumFromCache(acsTask.getLink_num());
|
// if (acsTask == null) throw new BadRequestException("被删除或无权限,操作失败!");
|
||||||
String link_no = CodeUtil.getNewCode("LINK_NO");
|
// List<TaskDto> tasksByLinkNum = this.findByLinkNumFromCache(acsTask.getLink_num());
|
||||||
if (tasksByLinkNum.size() == 1) {
|
// String link_no = CodeUtil.getNewCode("LINK_NO");
|
||||||
TaskDto taskDto = tasksByLinkNum.get(0);
|
// if (tasksByLinkNum.size() == 1) {
|
||||||
Instruction instruction = instructionService.findByTaskCodeFromCache(taskDto.getTask_code());
|
// TaskDto taskDto = tasksByLinkNum.get(0);
|
||||||
if (instruction != null) {
|
// Instruction instruction = instructionService.findByTaskCodeFromCache(taskDto.getTask_code());
|
||||||
throw new BadRequestException("单任务有指令未完成!指令号:" + instruction.getInstruction_code());
|
// if (instruction != null) {
|
||||||
}
|
// throw new BadRequestException("单任务有指令未完成!指令号:" + instruction.getInstruction_code());
|
||||||
Instruction dto = instructionService.createInstDtoByTask(taskDto, link_no);
|
// }
|
||||||
instructionService.create(dto);
|
// Instruction dto = instructionService.createInstDtoByTask(taskDto, link_no);
|
||||||
taskDto.setTask_status(StatusEnum.TASK_RUNNING.getCode());
|
// instructionService.create(dto);
|
||||||
this.update(taskDto);
|
// taskDto.setTask_status(StatusEnum.TASK_RUNNING.getCode());
|
||||||
}
|
// this.update(taskDto);
|
||||||
if (tasksByLinkNum.size() == 2) {
|
// }
|
||||||
TaskDto taskDto1 = tasksByLinkNum.get(0);
|
// if (tasksByLinkNum.size() == 2) {
|
||||||
Instruction inst1 = instructionService.findByTaskCodeFromCache(taskDto1.getTask_code());
|
// TaskDto taskDto1 = tasksByLinkNum.get(0);
|
||||||
if (inst1 != null) {
|
// Instruction inst1 = instructionService.findByTaskCodeFromCache(taskDto1.getTask_code());
|
||||||
throw new BadRequestException("双任务存有指令未完成!指令号:" + inst1.getInstruction_code());
|
// if (inst1 != null) {
|
||||||
}
|
// throw new BadRequestException("双任务存有指令未完成!指令号:" + inst1.getInstruction_code());
|
||||||
TaskDto taskDto2 = tasksByLinkNum.get(1);
|
// }
|
||||||
Instruction inst2 = instructionService.findByTaskCodeFromCache(taskDto2.getTask_code());
|
// TaskDto taskDto2 = tasksByLinkNum.get(1);
|
||||||
if (inst2 != null) {
|
// Instruction inst2 = instructionService.findByTaskCodeFromCache(taskDto2.getTask_code());
|
||||||
throw new BadRequestException("双任务有指令未完成!指令号:" + inst2.getInstruction_code());
|
// if (inst2 != null) {
|
||||||
}
|
// throw new BadRequestException("双任务有指令未完成!指令号:" + inst2.getInstruction_code());
|
||||||
Instruction dto1 = instructionService.createInstDtoByTask(taskDto1, link_no);
|
// }
|
||||||
Instruction dto2 = instructionService.createInstDtoByTask(taskDto2, link_no);
|
// Instruction dto1 = instructionService.createInstDtoByTask(taskDto1, link_no);
|
||||||
instructionService.createTwoInst(dto1, dto2);
|
// Instruction dto2 = instructionService.createInstDtoByTask(taskDto2, link_no);
|
||||||
taskDto1.setTask_status(StatusEnum.TASK_RUNNING.getCode());
|
// instructionService.createTwoInst(dto1, dto2);
|
||||||
taskDto1.setUpdate_time(DateUtil.now());
|
// taskDto1.setTask_status(StatusEnum.TASK_RUNNING.getCode());
|
||||||
this.update(taskDto1);
|
// taskDto1.setUpdate_time(DateUtil.now());
|
||||||
taskDto2.setTask_status(StatusEnum.TASK_RUNNING.getCode());
|
// this.update(taskDto1);
|
||||||
taskDto2.setUpdate_time(DateUtil.now());
|
// taskDto2.setTask_status(StatusEnum.TASK_RUNNING.getCode());
|
||||||
this.update(taskDto2);
|
// taskDto2.setUpdate_time(DateUtil.now());
|
||||||
}
|
// this.update(taskDto2);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package org.nl.acs.udw.mqttUdw;
|
||||||
|
|
||||||
|
import org.nl.acs.udw.UnifiedData;
|
||||||
|
import org.nl.acs.udw.mqttUdw.service.ItemData;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author onepiece
|
||||||
|
*/
|
||||||
|
public interface ItemsDataAccessor {
|
||||||
|
List<String> getAllKey();
|
||||||
|
|
||||||
|
Object getValue(String key);
|
||||||
|
|
||||||
|
void setValue(String key, Object value);
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package org.nl.acs.udw.mqttUdw;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import org.nl.acs.udw.UnifiedData;
|
||||||
|
import org.nl.acs.udw.mqttUdw.service.ItemData;
|
||||||
|
import org.nl.acs.udw.mqttUdw.service.ItemUnit;
|
||||||
|
import org.nl.acs.udw.service.impl.UnifiedDataUnit;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author onepiece
|
||||||
|
*/
|
||||||
|
public interface ItemsProcessService {
|
||||||
|
/**
|
||||||
|
* 获取所有的key
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<String> getAllUnifiedKey();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据key获取数据单元
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
ItemUnit getItemUnit(String key);
|
||||||
|
|
||||||
|
ItemData getItemData(String var1, String var2);
|
||||||
|
|
||||||
|
Object getValue(String var1, String var2);
|
||||||
|
|
||||||
|
void setValue(String var1, String var2, Object var3);
|
||||||
|
|
||||||
|
List<String> getAllDataKey(String var1);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package org.nl.acs.udw.mqttUdw.factory;
|
||||||
|
|
||||||
|
import org.nl.acs.udw.mqttUdw.ItemsDataAccessor;
|
||||||
|
import org.nl.acs.udw.mqttUdw.service.ItemsDataAccessorImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author onepiece
|
||||||
|
*/
|
||||||
|
public class ItemDataAccessorFactory {
|
||||||
|
|
||||||
|
private static final ItemsDataAccessorImpl itemsDataAccessor = new ItemsDataAccessorImpl();
|
||||||
|
|
||||||
|
public static ItemsDataAccessor getItemsDataAccessor(String unified_key) {
|
||||||
|
itemsDataAccessor.setUnifiedKey(unified_key);
|
||||||
|
itemsDataAccessor.setItemsProcess(ItemsProcessServiceFactory.getItemsUnifyProcess());
|
||||||
|
return itemsDataAccessor;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package org.nl.acs.udw.mqttUdw.factory;
|
||||||
|
|
||||||
|
import org.nl.acs.udw.mqttUdw.ItemsProcessService;
|
||||||
|
import org.nl.acs.udw.mqttUdw.service.ItemsProcessImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author onepiece
|
||||||
|
*/
|
||||||
|
public class ItemsProcessServiceFactory {
|
||||||
|
|
||||||
|
private static final ItemsProcessService itemsProcess = new ItemsProcessImpl();
|
||||||
|
|
||||||
|
|
||||||
|
public static ItemsProcessService getItemsUnifyProcess() {
|
||||||
|
return itemsProcess;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package org.nl.acs.udw.mqttUdw.service;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author onepiece
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ItemData {
|
||||||
|
private Object value;
|
||||||
|
private Date last_modify_date;
|
||||||
|
|
||||||
|
public ItemData() {
|
||||||
|
this.last_modify_date = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemData(Object value) {
|
||||||
|
this.value = value;
|
||||||
|
this.last_modify_date = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeValue(Object value) {
|
||||||
|
this.value = value;
|
||||||
|
this.last_modify_date = new Date();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package org.nl.acs.udw.mqttUdw.service;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.nl.acs.udw.UnifiedData;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author onepiece
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ItemUnit {
|
||||||
|
private String unifiedKey;
|
||||||
|
private Map<String, ItemData> storage = new ConcurrentHashMap<>();
|
||||||
|
private Map<String, List<ItemData>> history = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public ItemUnit(String unifiedKey) {
|
||||||
|
this.unifiedKey = unifiedKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package org.nl.acs.udw.mqttUdw.service;
|
||||||
|
|
||||||
|
import org.nl.acs.udw.mqttUdw.ItemsDataAccessor;
|
||||||
|
import org.nl.acs.udw.mqttUdw.ItemsProcessService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author onepiece
|
||||||
|
*/
|
||||||
|
public class ItemsDataAccessorImpl implements ItemsDataAccessor {
|
||||||
|
|
||||||
|
private String unified_key;
|
||||||
|
private ItemsProcessService itemsProcess;
|
||||||
|
|
||||||
|
|
||||||
|
public void setUnifiedKey(String unified_key) {
|
||||||
|
this.unified_key = unified_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setItemsProcess(ItemsProcessService itemsProcess) {
|
||||||
|
this.itemsProcess = itemsProcess;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAllKey() {
|
||||||
|
return this.itemsProcess.getAllDataKey(this.unified_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getValue(String key) {
|
||||||
|
return this.itemsProcess.getValue(this.unified_key, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setValue(String key, Object value) {
|
||||||
|
this.itemsProcess.setValue(this.unified_key, key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
package org.nl.acs.udw.mqttUdw.service;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.nl.acs.udw.UdwConfig;
|
||||||
|
import org.nl.acs.udw.UnifiedDataAppService;
|
||||||
|
import org.nl.acs.udw.mqttUdw.ItemsProcessService;
|
||||||
|
import org.nl.modules.common.exception.BadRequestException;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author onepiece
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class ItemsProcessImpl implements ItemsProcessService {
|
||||||
|
private Map<String, ItemUnit> factory = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public ItemsProcessImpl() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAllUnifiedKey() {
|
||||||
|
return new ArrayList(this.factory.keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemUnit getItemUnit(String unified_key) {
|
||||||
|
ItemUnit itemUnit = this.factory.get(unified_key);
|
||||||
|
return itemUnit == null ? null : itemUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAllDataKey(String unified_key) {
|
||||||
|
ItemUnit itemUnit = (ItemUnit) this.factory.get(unified_key);
|
||||||
|
if (itemUnit == null) {
|
||||||
|
return new ArrayList();
|
||||||
|
} else {
|
||||||
|
Map<String, ItemData> storage = itemUnit.getStorage();
|
||||||
|
return new ArrayList(storage.keySet());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemData getItemData(String unified_key, String key) {
|
||||||
|
ItemUnit itemUnit = this.getItemUnit(unified_key);
|
||||||
|
if (itemUnit == null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
Map<String, ItemData> storage = itemUnit.getStorage();
|
||||||
|
return (ItemData) storage.get(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getValue(String unified_key, String key) {
|
||||||
|
ItemData itemData = this.getItemData(unified_key, key);
|
||||||
|
return itemData == null ? null : itemData.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setValue(String unified_key, String key, Object value) {
|
||||||
|
this.setValue(unified_key, key, value, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public synchronized void setValue(String unified_key, String key, Object value, boolean save, boolean is_log) {
|
||||||
|
if (unified_key == null) {
|
||||||
|
throw new BadRequestException("");
|
||||||
|
//throw new BusinessException(SystemMessage.cant_be_empty, new Object[]{"unified_key"});
|
||||||
|
} else if (key == null) {
|
||||||
|
throw new BadRequestException("");
|
||||||
|
//throw new BusinessException(SystemMessage.cant_be_empty, new Object[]{"key"});
|
||||||
|
} else {
|
||||||
|
if (!this.factory.containsKey(unified_key)) {
|
||||||
|
this.factory.put(unified_key, new ItemUnit(unified_key));
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemUnit itemUnit = (ItemUnit) this.factory.get(unified_key);
|
||||||
|
Map<String, ItemData> storage = itemUnit.getStorage();
|
||||||
|
if (!storage.containsKey(key)) {
|
||||||
|
storage.put(key, new ItemData());
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemData itemData = (ItemData) storage.get(key);
|
||||||
|
if (!UnifiedDataAppService.isEquals(itemData.getValue(), value)) {
|
||||||
|
Map<String, List<ItemData>> history = itemUnit.getHistory();
|
||||||
|
List<ItemData> historyItemDatas = (List) history.get(key);
|
||||||
|
if (historyItemDatas == null) {
|
||||||
|
history.put(key, new ArrayList());
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemData historyData = new ItemData();
|
||||||
|
historyData.setLast_modify_date(itemData.getLast_modify_date());
|
||||||
|
historyData.setValue(itemData.getValue());
|
||||||
|
|
||||||
|
while (((List) history.get(key)).size() > UdwConfig.max_history_length) {
|
||||||
|
((List) history.get(key)).remove(UdwConfig.max_history_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
((List) history.get(key)).add(0, historyData);
|
||||||
|
Object oldvalue = itemData.getValue();
|
||||||
|
itemData.changeValue(value);
|
||||||
|
if (save) {
|
||||||
|
/*PersistenceService persistenceService = PersistenceServiceFactory.getPersistenceService();
|
||||||
|
persistenceService.saveData(unified_key, key, StringUtl.getString(value));
|
||||||
|
if (is_log) {
|
||||||
|
this.businessLogger.setResource(unified_key, unified_key);
|
||||||
|
this.businessLogger.setMaterial(key, key);
|
||||||
|
this.businessLogger.setContainer(StringUtl.getString(value));
|
||||||
|
this.businessLogger.log("统一数据源中: unit: {}, key: {}, 值: {} 更改为 {}。", new Object[]{unified_key, key, oldvalue, value});
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_log && key != null && !key.endsWith("heartbeat") && !key.endsWith("distancex") && !key.endsWith("distancey") && !key.endsWith("Xwz") && !key.endsWith("Ywz") && !key.endsWith("Zwz")) {
|
||||||
|
log.trace("统一数据源中: unit: {}, key: {}, 值: {} 更改为 {}。", new Object[]{unified_key, key, oldvalue, value});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package org.nl.config.mqtt2;
|
||||||
|
|
||||||
|
import org.nl.acs.device_driver.DeviceDriver;
|
||||||
|
import org.nl.acs.device_driver.driver.AbstractDeviceDriver;
|
||||||
|
import org.nl.acs.opc.Device;
|
||||||
|
import org.nl.acs.opc.DeviceAppService;
|
||||||
|
import org.nl.config.mqtt2.msg.DeviceItemData;
|
||||||
|
import org.nl.modules.wql.util.SpringContextHolder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description TODO
|
||||||
|
* @Author Gengby
|
||||||
|
* @Date 2024/3/18
|
||||||
|
*/
|
||||||
|
public class ItemUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 心跳item名称
|
||||||
|
*/
|
||||||
|
private static final String HEARTBEAT = "heartbeat";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定符合索引
|
||||||
|
*
|
||||||
|
* @param text itemId
|
||||||
|
* @param character 指定符合
|
||||||
|
* @param n 第几个富豪
|
||||||
|
* @return 索引
|
||||||
|
*/
|
||||||
|
public static int nthIndexOf(String text, String character, int n) {
|
||||||
|
int position = -1;
|
||||||
|
do {
|
||||||
|
position = text.indexOf(character, position + 1);
|
||||||
|
} while (n-- > 1 && position != -1);
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hasHeartbeat(String itemId) {
|
||||||
|
return itemId.contains(HEARTBEAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setIsOnline(DeviceAppService deviceAppService, String deviceCode, List<DeviceItemData> items) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
package org.nl.config.mqtt2;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.eclipse.paho.client.mqttv3.MqttClient;
|
|
||||||
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
|
||||||
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
|
||||||
import org.nl.config.mqtt2.callback.PublishCallback;
|
|
||||||
import org.nl.config.mqtt2.callback.SubsribeCallback;
|
|
||||||
import org.nl.config.mqtt2.config.MqttConfig;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @author ZZQ
|
|
||||||
* @Date 2024/1/31 14:07
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
@ConditionalOnProperty(name = "mqtt.active", havingValue = "true")
|
|
||||||
public class MQServer {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private MqttConfig mqttConfig;
|
|
||||||
|
|
||||||
public static MqttClient subsribeClient;
|
|
||||||
|
|
||||||
public static MqttClient publishClient;
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void init() throws Exception {
|
|
||||||
this.initSubsribe();
|
|
||||||
this.initPublish();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void sendMsg(String topic,String body,int qos,Boolean retained){
|
|
||||||
try {
|
|
||||||
if (publishClient!=null && StringUtils.isNotEmpty(body)){
|
|
||||||
MqttMessage message = new MqttMessage();
|
|
||||||
message.setQos(qos);
|
|
||||||
message.setRetained(retained);
|
|
||||||
message.setPayload(body.getBytes());
|
|
||||||
publishClient.publish(topic,message);
|
|
||||||
}
|
|
||||||
}catch (Exception ex){
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void shutdown() throws Exception {
|
|
||||||
subsribeClient.disconnect();
|
|
||||||
publishClient.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initSubsribe() throws Exception {
|
|
||||||
if (subsribeClient!=null){
|
|
||||||
System.out.println("重新连接");
|
|
||||||
subsribeClient.disconnect();
|
|
||||||
}
|
|
||||||
subsribeClient = new MqttClient(mqttConfig.getUrl(), mqttConfig.getClientId(), new MemoryPersistence());
|
|
||||||
subsribeClient.connect(mqttConfig.getOption());
|
|
||||||
subsribeClient.setCallback(new SubsribeCallback());
|
|
||||||
subsribeClient.subscribe(mqttConfig.getTopics());
|
|
||||||
}
|
|
||||||
private void initPublish() throws Exception {
|
|
||||||
if (publishClient!=null){
|
|
||||||
System.out.println("重新连接");
|
|
||||||
publishClient.disconnect();
|
|
||||||
}
|
|
||||||
publishClient = new MqttClient(mqttConfig.getUrl(), UUID.randomUUID().toString(), new MemoryPersistence());
|
|
||||||
publishClient.connect(mqttConfig.getOption());
|
|
||||||
publishClient.setCallback(new PublishCallback());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,412 @@
|
|||||||
|
package org.nl.config.mqtt2;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import io.micrometer.core.instrument.util.NamedThreadFactory;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.eclipse.paho.client.mqttv3.*;
|
||||||
|
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
||||||
|
import org.nl.acs.auto.initial.ApplicationAutoInitial;
|
||||||
|
import org.nl.acs.device.service.OpcService;
|
||||||
|
import org.nl.acs.device.service.dto.OpcDto;
|
||||||
|
import org.nl.acs.device_driver.driver.AbstractDeviceDriver;
|
||||||
|
import org.nl.acs.opc.Device;
|
||||||
|
import org.nl.acs.opc.DeviceAppService;
|
||||||
|
import org.nl.acs.opc.OpcConfig;
|
||||||
|
import org.nl.acs.opc.OpcServerService;
|
||||||
|
import org.nl.acs.udw.mqttUdw.ItemsDataAccessor;
|
||||||
|
import org.nl.acs.udw.mqttUdw.factory.ItemDataAccessorFactory;
|
||||||
|
import org.nl.config.mqtt2.config.MqttConfig;
|
||||||
|
import org.nl.config.mqtt2.msg.DeviceItemData;
|
||||||
|
import org.nl.modules.lucene.service.LuceneExecuteLogService;
|
||||||
|
import org.nl.modules.lucene.service.dto.LuceneLogDto;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description TODO
|
||||||
|
* @Author Gengby
|
||||||
|
* @Date 2024/3/15
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@ConditionalOnProperty(name = "mqtt.active", havingValue = "true")
|
||||||
|
@ConditionalOnBean({LuceneExecuteLogService.class, OpcServerService.class, DeviceAppService.class})
|
||||||
|
@Slf4j
|
||||||
|
public class MqttServer implements MqttCallback, ApplicationAutoInitial {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MqttConfig mqttConfig;
|
||||||
|
@Autowired
|
||||||
|
private RedisTemplate redisTemplate;
|
||||||
|
@Autowired
|
||||||
|
private LuceneExecuteLogService logService;
|
||||||
|
@Autowired
|
||||||
|
private OpcService opcService;
|
||||||
|
@Autowired
|
||||||
|
private DeviceAppService deviceAppService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据topic存储订阅消息
|
||||||
|
*/
|
||||||
|
private final Map<String, LinkedBlockingQueue<String>> topicMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存储设备点位信息
|
||||||
|
*/
|
||||||
|
private static final ItemsDataAccessor ACCESSOR_VALUE = ItemDataAccessorFactory.getItemsDataAccessor(OpcConfig.udw_opc_value_key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发布TOPIC
|
||||||
|
*/
|
||||||
|
private static final String PUBLISH_TOPIC = "publishTopic";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重连开启一个新的线程
|
||||||
|
*/
|
||||||
|
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重连延迟时间,单位:毫秒
|
||||||
|
*/
|
||||||
|
private static final long RECONNECT_DELAY = 5000L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重连标记
|
||||||
|
*/
|
||||||
|
private volatile boolean reconnectingFlag = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存储Redis数据Key
|
||||||
|
*/
|
||||||
|
private static final String KEY = "opc:items";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 心跳item名称
|
||||||
|
*/
|
||||||
|
private static final String HEARTBEAT = "heartbeat";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MQTT客户端
|
||||||
|
*/
|
||||||
|
private MqttClient mqttClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MQTT QOS级别 这里默认的使用的是QOS_2
|
||||||
|
* 0 最多交付一次 可能导致消息丢失
|
||||||
|
* 1 最少交付一次 可能导致消息重复
|
||||||
|
* 2 只交付一次 保证消息不会丢失和重复
|
||||||
|
*/
|
||||||
|
private static final int QOS_0 = 0;
|
||||||
|
private static final int QOS_1 = 1;
|
||||||
|
private static final int QOS_2 = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 线程池核心线程数量
|
||||||
|
*/
|
||||||
|
private static final int CORE_POOL_SIZE = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 线程池最大线程数量
|
||||||
|
*/
|
||||||
|
private static final int MAX_POOL_SIZE = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 非核心线程存活时间
|
||||||
|
*/
|
||||||
|
private static final int KEEP_ALIVE_TIME = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用来存储等待执行任务的阻塞队列的大小
|
||||||
|
*/
|
||||||
|
private static final int WORK_QUEUE_SIZE = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 队列
|
||||||
|
*/
|
||||||
|
private static final Queue<Runnable> MSG_QUEUE = new LinkedBlockingQueue<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 线程工厂
|
||||||
|
*/
|
||||||
|
private final ThreadFactory threadFactory = new NamedThreadFactory("MqttThreadFactory");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 线程池
|
||||||
|
*/
|
||||||
|
private final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
|
||||||
|
CORE_POOL_SIZE,
|
||||||
|
MAX_POOL_SIZE,
|
||||||
|
KEEP_ALIVE_TIME,
|
||||||
|
TimeUnit.SECONDS,
|
||||||
|
new ArrayBlockingQueue<>(WORK_QUEUE_SIZE),
|
||||||
|
threadFactory,
|
||||||
|
(r, executor) -> MSG_QUEUE.add(r)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void autoInitial() throws Exception {
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void init() throws Exception {
|
||||||
|
this.initTopicMap();
|
||||||
|
this.initMqttClient();
|
||||||
|
this.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化topicMap
|
||||||
|
* <p>
|
||||||
|
* 从数据库中查询所有的topic
|
||||||
|
* 并为每个topic初始化一个队列,分别存储其订阅的消息
|
||||||
|
*/
|
||||||
|
private void initTopicMap() {
|
||||||
|
log.info("init topicMap...");
|
||||||
|
List<OpcDto> opcDtos = opcService.queryAll(null);
|
||||||
|
//根据配置OPC信息动态调整核心线程池个数
|
||||||
|
threadPool.setCorePoolSize(opcDtos.size() + 1);
|
||||||
|
threadPool.setMaximumPoolSize(opcDtos.size() + 10);
|
||||||
|
opcDtos.forEach(opcDto -> topicMap.put(opcDto.getTopic(), new LinkedBlockingQueue<>()));
|
||||||
|
log.info("init topicMap finish");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化MQTT客户端
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private void initMqttClient() throws Exception {
|
||||||
|
log.info("init mqtt client...");
|
||||||
|
if (mqttClient != null) {
|
||||||
|
mqttClient.disconnect();
|
||||||
|
}
|
||||||
|
mqttClient = new MqttClient(mqttConfig.getUrl(), mqttConfig.getClientId(), new MemoryPersistence());
|
||||||
|
mqttClient.connect(mqttConfig.getOption());
|
||||||
|
mqttClient.setCallback(this);
|
||||||
|
mqttClient.subscribe(mqttConfig.getTopics(), mqttConfig.getQoss());
|
||||||
|
log.info("init mqtt client finish");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void run() {
|
||||||
|
topicMap.forEach((topic, values) -> threadPool.execute(() -> {
|
||||||
|
try {
|
||||||
|
log.info("create topic thread:{}", topic);
|
||||||
|
while (true) {
|
||||||
|
String message = values.take();
|
||||||
|
execute(topic, message);
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("topic:{} , msg handle failed: {}", topic, e.getMessage());
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void execute(String topic, String body) {
|
||||||
|
JSONObject msg = JSONObject.parseObject(body);
|
||||||
|
JSONArray msgValues = msg.getJSONArray("values");
|
||||||
|
List<DeviceItemData> itemDataList = msgValues.toJavaList(DeviceItemData.class);
|
||||||
|
Map<String, List<DeviceItemData>> map = itemDataList.stream().collect(Collectors.groupingBy(deviceData -> {
|
||||||
|
int thirdDotIndex = ItemUtil.nthIndexOf(deviceData.getId(), ".", 3);
|
||||||
|
return deviceData.getId().substring(0, thirdDotIndex);
|
||||||
|
}));
|
||||||
|
map.forEach((itemId, items) -> {
|
||||||
|
int startIndex = ItemUtil.nthIndexOf(itemId, ".", 2) + 1;
|
||||||
|
items.stream().anyMatch(item -> ItemUtil.hasHeartbeat(item.getId()));
|
||||||
|
String deviceCode = itemId.substring(startIndex);
|
||||||
|
Optional<Boolean> vOptional = items.stream()
|
||||||
|
.filter(item -> item.getId().contains(HEARTBEAT))
|
||||||
|
.map(DeviceItemData::isQ)
|
||||||
|
.findFirst();
|
||||||
|
vOptional.ifPresent(q -> {
|
||||||
|
Device device = deviceAppService.findDeviceByCode(deviceCode);
|
||||||
|
if (device != null && device.getDeviceDriver() instanceof AbstractDeviceDriver) {
|
||||||
|
AbstractDeviceDriver deviceDriver = (AbstractDeviceDriver) device.getDeviceDriver();
|
||||||
|
if (!Objects.equals(deviceDriver.getOnline(), q)) {
|
||||||
|
deviceDriver.setOnline(q);
|
||||||
|
log.info("device:{},online status:{}", deviceCode, q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setValue(deviceCode, items);
|
||||||
|
});
|
||||||
|
System.out.println("线程名称:'" + Thread.currentThread() + "',接收到消息" + topic + "-" + body + "-");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更改内存中的值
|
||||||
|
*
|
||||||
|
* @param deviceCode
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
private void setValue(String deviceCode, List<DeviceItemData> value) {
|
||||||
|
value.forEach(deviceData -> {
|
||||||
|
logService.deviceExecuteLog(new LuceneLogDto(deviceCode, "MQTT上报,信号:" + deviceData.getId() + ",由" + ACCESSOR_VALUE.getValue(deviceData.getId()) + "->" + deviceData.getV() + ",信号健康值:" + deviceData.isQ()));
|
||||||
|
ACCESSOR_VALUE.setValue(deviceData.getId(), deviceData.getV());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 断开连接执行逻辑
|
||||||
|
*
|
||||||
|
* @param cause
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void connectionLost(Throwable cause) {
|
||||||
|
log.info("mqtt client break link");
|
||||||
|
if (!reconnectingFlag) {
|
||||||
|
reconnectingFlag = true;
|
||||||
|
scheduler.execute(() -> {
|
||||||
|
while (!mqttClient.isConnected()) {
|
||||||
|
try {
|
||||||
|
if (!mqttClient.isConnected()) {
|
||||||
|
mqttClient.reconnect();
|
||||||
|
log.info("mqtt client again success");
|
||||||
|
}
|
||||||
|
} catch (MqttException e) {
|
||||||
|
log.error("mqtt client again failed: {}", e.getMessage());
|
||||||
|
try {
|
||||||
|
Thread.sleep(RECONNECT_DELAY);
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reconnectingFlag = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订阅topic
|
||||||
|
*
|
||||||
|
* @param topic 主题
|
||||||
|
* @param message 内容
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void messageArrived(String topic, MqttMessage message) throws Exception {
|
||||||
|
//接收到消息:先放队列,根据不同topic处理不同处理dd逻辑
|
||||||
|
if (topicMap.containsKey(topic)) {
|
||||||
|
topicMap.get(topic).add(new String(message.getPayload()));
|
||||||
|
System.out.println("接收到消息---" + topic + "内容:" + new String(message.getPayload()));
|
||||||
|
} else {
|
||||||
|
log.info("topic---{} does not exist", topic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发布结果处理
|
||||||
|
*
|
||||||
|
* @param token
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
@Override
|
||||||
|
public void deliveryComplete(IMqttDeliveryToken token) {
|
||||||
|
boolean complete = token.isComplete();
|
||||||
|
MqttMessage message = token.getMessage();
|
||||||
|
String[] topics = token.getTopics();
|
||||||
|
log.info("message publish result ,topic:{},message:{},complete:{}", Arrays.toString(topics), new String(message.getPayload()), complete);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息发布
|
||||||
|
*
|
||||||
|
* @param body MQTT下发数据的格式是
|
||||||
|
* [
|
||||||
|
* {"id":"opc_code.plc_code.device_code.item","v":value},
|
||||||
|
* {"id":"opc_code.plc_code.device_code.item","v":value}
|
||||||
|
* ]
|
||||||
|
*/
|
||||||
|
public void sendMsg(String body) {
|
||||||
|
try {
|
||||||
|
synchronized (this) {
|
||||||
|
if (mqttClient != null && StringUtils.isNotEmpty(body)) {
|
||||||
|
MqttMessage message = new MqttMessage();
|
||||||
|
message.setQos(QOS_2);
|
||||||
|
message.setRetained(true);
|
||||||
|
message.setPayload(body.getBytes());
|
||||||
|
mqttClient.publish(PUBLISH_TOPIC, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
log.error("message publish failed:{}", ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void start() {
|
||||||
|
loadItems();
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||||
|
System.out.println("----close threadPool-----");
|
||||||
|
try {
|
||||||
|
shutdown();
|
||||||
|
unloadItems();
|
||||||
|
threadPool.shutdown();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭MQTT客户端连接
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public void shutdown() throws Exception {
|
||||||
|
log.info("close mqtt client...");
|
||||||
|
mqttClient.disconnect();
|
||||||
|
log.info("close mqtt client finish");
|
||||||
|
|
||||||
|
log.info("close scheduler...");
|
||||||
|
scheduler.shutdown();
|
||||||
|
log.info("close scheduler finish...");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从redis写入内存 item数据
|
||||||
|
*/
|
||||||
|
private void loadItems() {
|
||||||
|
log.info("loading...");
|
||||||
|
Map<Object, Object> entries = redisTemplate.opsForHash().entries(KEY);
|
||||||
|
entries.forEach((key, value) -> ACCESSOR_VALUE.setValue((String) key, value));
|
||||||
|
log.info("load finish, delete key...");
|
||||||
|
redisTemplate.delete(KEY);
|
||||||
|
log.info("delete finish!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从内存写出到redis item数据
|
||||||
|
*/
|
||||||
|
private void unloadItems() {
|
||||||
|
log.info("unloading...");
|
||||||
|
List<String> allKey = ACCESSOR_VALUE.getAllKey();
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
allKey.forEach(key -> map.put(key, ACCESSOR_VALUE.getValue(key)));
|
||||||
|
log.info("unload finish, put key...");
|
||||||
|
redisTemplate.opsForHash().putAll(KEY, map);
|
||||||
|
log.info("put finish!");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package org.nl.config.mqtt2;
|
|
||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaIgnore;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @author ZZQ
|
|
||||||
* @Date 2024/1/31 17:12
|
|
||||||
*/
|
|
||||||
//@RestController
|
|
||||||
public class PublishDemo {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
MQServer server;
|
|
||||||
|
|
||||||
@RequestMapping("/publish")
|
|
||||||
@SaIgnore
|
|
||||||
public void send(String topic,String msg){
|
|
||||||
MQServer.sendMsg(topic,msg,1,true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequestMapping("/init")
|
|
||||||
@SaIgnore
|
|
||||||
public void d222() throws Exception {
|
|
||||||
server.init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package org.nl.config.mqtt2.callback;
|
|
||||||
|
|
||||||
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
|
|
||||||
import org.eclipse.paho.client.mqttv3.MqttCallback;
|
|
||||||
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @author ZZQ
|
|
||||||
* @Date 2024/1/31 13:55
|
|
||||||
*/
|
|
||||||
public class PublishCallback implements MqttCallback {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void connectionLost(Throwable throwable) {
|
|
||||||
//重连,调用服务初始化init
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
|
|
||||||
//接收到消息:先放队列,根据不同topic处理不同处理逻辑
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
|
|
||||||
//消息接收成功后
|
|
||||||
boolean complete = iMqttDeliveryToken.isComplete();
|
|
||||||
System.out.println("消息处理结果:"+complete);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package org.nl.config.mqtt2.callback;
|
|
||||||
|
|
||||||
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
|
|
||||||
import org.eclipse.paho.client.mqttv3.MqttCallback;
|
|
||||||
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
|
||||||
import org.nl.config.mqtt2.msg.MsgPoolManager;
|
|
||||||
import org.nl.config.mqtt2.msg.MsgWorker;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @author ZZQ
|
|
||||||
* @Date 2024/1/31 13:55
|
|
||||||
*/
|
|
||||||
public class SubsribeCallback implements MqttCallback {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void connectionLost(Throwable throwable) {
|
|
||||||
//重连,调用服务初始化init
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
|
|
||||||
//接收到消息:先放队列,根据不同topic处理不同处理dd逻辑
|
|
||||||
System.out.println("接收到消息topic:"+topic+"——"+new String(mqttMessage.getPayload()));
|
|
||||||
MsgPoolManager.hander(new MsgWorker(topic,new String(mqttMessage.getPayload())));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
|
|
||||||
//消息接收如果处理失败允许在这里重试
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,7 +4,14 @@ import lombok.Data;
|
|||||||
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.integration.dsl.IntegrationFlow;
|
||||||
|
import org.springframework.integration.dsl.IntegrationFlows;
|
||||||
|
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
|
||||||
|
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
|
||||||
|
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
|
||||||
|
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
@@ -29,6 +36,8 @@ public class MqttConfig {
|
|||||||
|
|
||||||
private String[] topics;
|
private String[] topics;
|
||||||
|
|
||||||
|
private int[] qoss;
|
||||||
|
|
||||||
private int timeout;
|
private int timeout;
|
||||||
|
|
||||||
private int keepalive;
|
private int keepalive;
|
||||||
@@ -36,23 +45,22 @@ public class MqttConfig {
|
|||||||
private MqttConnectOptions option;
|
private MqttConnectOptions option;
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void initOption(){
|
public void initOption() {
|
||||||
MqttConnectOptions options = new MqttConnectOptions();
|
MqttConnectOptions options = new MqttConnectOptions();
|
||||||
// 设定清除会话信息,true时,每次连接都会建立新的会话,false时,服务端会保留会话信息
|
// 设定清除会话信息,true时,每次连接都会建立新的会话,false时,服务端会保留会话信息
|
||||||
options.setCleanSession(true);
|
options.setCleanSession(false);
|
||||||
//options.setCleanSession(true);
|
|
||||||
// 设定重连机制,设定为true时,mqtt的重连机制会启动,当mqtt client掉线之后它会进入重连
|
// 设定重连机制,设定为true时,mqtt的重连机制会启动,当mqtt client掉线之后它会进入重连
|
||||||
options.setAutomaticReconnect(true);
|
options.setAutomaticReconnect(true);
|
||||||
if (!username.equals("a")){
|
options.setUserName(username);
|
||||||
options.setUserName(username);
|
options.setPassword(password.toCharArray());
|
||||||
}
|
|
||||||
if (!password.equals("a")){
|
|
||||||
options.setPassword(password.toCharArray());
|
|
||||||
}
|
|
||||||
options.setConnectionTimeout(timeout);
|
options.setConnectionTimeout(timeout);
|
||||||
options.setKeepAliveInterval(keepalive);
|
options.setKeepAliveInterval(keepalive);
|
||||||
|
|
||||||
// 设置“遗嘱”消息的话题,若客户端与服务器之间的连接意外中断,服务器将发布客户端的“遗嘱”消息。
|
// 设置“遗嘱”消息的话题,若客户端与服务器之间的连接意外中断,服务器将发布客户端的“遗嘱”消息。
|
||||||
//options.setWill("willTopic", WILL_DATA, 2, false);
|
//options.setWill("willTopic", WILL_DATA, 2, false);
|
||||||
option=options;
|
option = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package org.nl.config.mqtt2.msg;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description TODO
|
||||||
|
* @Author Gengby
|
||||||
|
* @Date 2024/3/5
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class DeviceItemData<T> {
|
||||||
|
private String id;
|
||||||
|
private T v;
|
||||||
|
private boolean q;
|
||||||
|
private long t;
|
||||||
|
}
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
package org.nl.config.mqtt2.msg;
|
|
||||||
|
|
||||||
import org.nl.config.mqtt2.MQServer;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.concurrent.*;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @author ZZQ
|
|
||||||
* @Date 2024/1/31 15:19
|
|
||||||
* 待确认:1.所有消走线程还是先走队列;2.同一个topic消息处理需要保证消费顺序3.消息写时订阅也会订阅毁掉会拿到自己写的信息
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@ConditionalOnBean(value = MQServer.class)
|
|
||||||
public class MsgPoolManager {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
MQServer mqServer;
|
|
||||||
// 线程池维护线程的最少数量
|
|
||||||
private final static int CORE_POOL_SIZE = 2;
|
|
||||||
// 线程池维护线程的最大数量
|
|
||||||
private final static int MAX_POOL_SIZE = 20 ;
|
|
||||||
// 线程池维护线程所允许的空闲时间
|
|
||||||
private final static int KEEP_ALIVE_TIME = 10;
|
|
||||||
// 线程池 所使用的缓存队列大小
|
|
||||||
private final static int WORK_QUEUE_SIZE = 1000;
|
|
||||||
|
|
||||||
|
|
||||||
private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5);
|
|
||||||
|
|
||||||
|
|
||||||
static Queue<Runnable> msgQueue = new LinkedBlockingQueue<>();
|
|
||||||
|
|
||||||
static ThreadPoolExecutor threadPool =null;
|
|
||||||
|
|
||||||
static ScheduledFuture scheduledFuture =null;
|
|
||||||
|
|
||||||
static {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void hander(MsgWorker r){
|
|
||||||
threadPool.execute(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void start() {
|
|
||||||
threadPool = new ThreadPoolExecutor(CORE_POOL_SIZE,MAX_POOL_SIZE,
|
|
||||||
KEEP_ALIVE_TIME, TimeUnit.SECONDS,new ArrayBlockingQueue<>(WORK_QUEUE_SIZE), (r, executor) -> msgQueue.add(r));
|
|
||||||
|
|
||||||
// scheduledFuture = scheduler.scheduleAtFixedRate(() -> {
|
|
||||||
// // 判断缓存队列是否存在记录
|
|
||||||
// System.out.println("定时任务启动"+msgQueue.size());
|
|
||||||
// if(!msgQueue.isEmpty()){
|
|
||||||
// if(threadPool.getQueue().size() < WORK_QUEUE_SIZE){
|
|
||||||
// Runnable worker = msgQueue.poll();
|
|
||||||
// threadPool.execute(worker);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// },0,1,TimeUnit.SECONDS);
|
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
|
||||||
System.out.println("----关闭线程池-----");
|
|
||||||
try {
|
|
||||||
mqServer.shutdown();
|
|
||||||
threadPool.shutdown();
|
|
||||||
// scheduler.shutdown();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package org.nl.config.mqtt2.msg;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @author ZZQ
|
|
||||||
* @Date 2024/1/31 15:29
|
|
||||||
* 消息处理线程:通过线程池处理:如果需要用到具体topic的handler:可以传入
|
|
||||||
*/
|
|
||||||
public class MsgWorker implements Runnable{
|
|
||||||
/**
|
|
||||||
* topic
|
|
||||||
*/
|
|
||||||
public String topic;
|
|
||||||
/**
|
|
||||||
* 消息体
|
|
||||||
*/
|
|
||||||
private String body;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
System.out.println("接收到消息"+topic+"-"+body);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MsgWorker(String topic, String body) {
|
|
||||||
this.topic = topic;
|
|
||||||
this.body = body;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,6 @@ import org.nl.acs.acsEnum.StatusEnum;
|
|||||||
import org.nl.acs.instruction.service.InstructionService;
|
import org.nl.acs.instruction.service.InstructionService;
|
||||||
import org.nl.acs.task.service.TaskService;
|
import org.nl.acs.task.service.TaskService;
|
||||||
import org.nl.acs.task.service.dto.TaskDto;
|
import org.nl.acs.task.service.dto.TaskDto;
|
||||||
import org.nl.modules.system.util.CodeUtil;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -32,14 +31,13 @@ public class AutoCreateAgvOneInst {
|
|||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
List<TaskDto> list = taskService.queryAll("task_status = '0' and (agv_system_type = '2' or agv_system_type = '3')");
|
List<TaskDto> list = taskService.queryAll("task_status = '0' and agv_system_type = '2'");
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (int i = 0; i < list.size(); i++) {
|
||||||
TaskDto taskDto = list.get(i);
|
TaskDto taskDto = list.get(i);
|
||||||
String link_no = CodeUtil.getNewCode("LINK_NO");
|
|
||||||
try {
|
try {
|
||||||
instructionService.create(instructionService.createInstDtoByTask(taskDto, link_no));
|
instructionService.autoCreateOneInst(instructionService.createInstDtoByTask(taskDto));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("自动创建指令失败:任务号{},失败原因:{}", taskDto.getTask_code(), e.getMessage());
|
log.error("自动创建叉车指令失败:任务号{},失败原因:{}", taskDto.getTask_code(), e.getMessage());
|
||||||
taskDto.setRemark(e.getMessage());
|
taskDto.setRemark(e.getMessage());
|
||||||
taskService.updateByCodeFromCache(taskDto);
|
taskService.updateByCodeFromCache(taskDto);
|
||||||
continue;
|
continue;
|
||||||
@@ -47,7 +45,7 @@ public class AutoCreateAgvOneInst {
|
|||||||
//创建指令后修改任务状态
|
//创建指令后修改任务状态
|
||||||
taskDto.setTask_status(StatusEnum.TASK_RUNNING.getCode());
|
taskDto.setTask_status(StatusEnum.TASK_RUNNING.getCode());
|
||||||
taskService.update(taskDto);
|
taskService.update(taskDto);
|
||||||
log.info("自动创建指令成功,任务号:{}", taskDto.getTask_code());
|
log.info("自动创建叉车指令成功,任务号:{}", taskDto.getTask_code());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package org.nl.modules.quartz.task;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.nl.acs.acsEnum.StatusEnum;
|
||||||
|
import org.nl.acs.instruction.service.InstructionService;
|
||||||
|
import org.nl.acs.task.service.TaskService;
|
||||||
|
import org.nl.acs.task.service.dto.TaskDto;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动创建海柔AGV指令
|
||||||
|
*
|
||||||
|
* @author GengBy
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class AutoCreateHrInst {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private InstructionService instructionService;
|
||||||
|
@Autowired
|
||||||
|
private TaskService taskService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 海柔最大指令数量
|
||||||
|
*/
|
||||||
|
private static final int MAX_INST_NUM = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询海柔AGV任务并生成对应的指令
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public void run() throws Exception {
|
||||||
|
List<TaskDto> list = taskService.queryAll("task_status = '0' and agv_system_type = '3'");
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
TaskDto taskDto = list.get(i);
|
||||||
|
try {
|
||||||
|
int maxNum = instructionService.querySameDeviceCodeForHrMaxNum(taskDto.getStart_point_code(), taskDto.getNext_point_code());
|
||||||
|
if (maxNum == MAX_INST_NUM) {
|
||||||
|
log.info("海柔同一点位指令数量大于允许生成的最大指令数量:" + MAX_INST_NUM);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
instructionService.autoCreateHrInst(instructionService.createInstDtoByTask(taskDto));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("自动创建海柔指令失败:任务号{},失败原因:{}", taskDto.getTask_code(), e.getMessage());
|
||||||
|
taskDto.setRemark(e.getMessage());
|
||||||
|
taskService.updateByCodeFromCache(taskDto);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//创建指令后修改任务状态
|
||||||
|
taskDto.setTask_status(StatusEnum.TASK_RUNNING.getCode());
|
||||||
|
taskService.update(taskDto);
|
||||||
|
log.info("自动创建海柔指令成功,任务号:{}", taskDto.getTask_code());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -114,7 +114,7 @@ public class AutoCreateInst {
|
|||||||
//生产指令关联编号
|
//生产指令关联编号
|
||||||
String link_no = CodeUtil.getNewCode("LINK_NO");
|
String link_no = CodeUtil.getNewCode("LINK_NO");
|
||||||
|
|
||||||
Instruction instDto = instructionService.createInstDtoByTask(taskDto, link_no);
|
Instruction instDto = instructionService.createInstDtoByTask(taskDto);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
instructionService.create(instDto);
|
instructionService.create(instDto);
|
||||||
@@ -152,9 +152,8 @@ public class AutoCreateInst {
|
|||||||
//生产指令关联编号
|
//生产指令关联编号
|
||||||
String link_no = CodeUtil.getNewCode("LINK_NO");
|
String link_no = CodeUtil.getNewCode("LINK_NO");
|
||||||
|
|
||||||
|
Instruction instDto1 = instructionService.createInstDtoByTask(taskDto1);
|
||||||
Instruction instDto1 = instructionService.createInstDtoByTask(taskDto1, link_no);
|
Instruction instDto2 = instructionService.createInstDtoByTask(taskDto2);
|
||||||
Instruction instDto2 = instructionService.createInstDtoByTask(taskDto2, link_no);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
instructionService.createTwoInst(instDto1, instDto2);
|
instructionService.createTwoInst(instDto1, instDto2);
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
package org.nl.modules.quartz.task;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.nl.acs.acsEnum.StatusEnum;
|
||||||
|
import org.nl.acs.instruction.service.InstructionService;
|
||||||
|
import org.nl.acs.instruction.service.dto.Instruction;
|
||||||
|
import org.nl.acs.opc.DeviceAppService;
|
||||||
|
import org.nl.acs.task.service.TaskService;
|
||||||
|
import org.nl.acs.task.service.dto.TaskDto;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动创建诺宝AGV指令
|
||||||
|
*
|
||||||
|
* @author GengBy
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class AutoCreateNuoBaoInst {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TaskService taskService;
|
||||||
|
@Autowired
|
||||||
|
private InstructionService instructionService;
|
||||||
|
@Autowired
|
||||||
|
private DeviceAppService deviceAppService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单任务个数
|
||||||
|
*/
|
||||||
|
public static final Integer TASK_SIZE_1 = 1;
|
||||||
|
/**
|
||||||
|
* 双任务个数
|
||||||
|
*/
|
||||||
|
public static final Integer TASK_SIZE_2 = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动创建诺宝AGV指令
|
||||||
|
*/
|
||||||
|
public void run() throws Exception {
|
||||||
|
|
||||||
|
//查询所有诺宝AGV任务
|
||||||
|
List<TaskDto> list = taskService.queryAll("task_status = '0' and agv_system_type = '1' ");
|
||||||
|
|
||||||
|
if (ObjectUtil.isEmpty(list)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//根据LINK_NUM分组任务
|
||||||
|
Map<String, List<TaskDto>> link_num_tasks = Optional
|
||||||
|
.ofNullable(list)
|
||||||
|
.orElse(new ArrayList<>())
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.groupingBy(TaskDto::getLink_num));
|
||||||
|
//遍历分组任务 如果任务数为2则是下发双任务,如果任务数为1 则下发单任务
|
||||||
|
for (Map.Entry<String, List<TaskDto>> task_values : link_num_tasks.entrySet()) {
|
||||||
|
List<TaskDto> tasks =
|
||||||
|
Optional
|
||||||
|
.ofNullable(task_values.getValue())
|
||||||
|
.orElse(new ArrayList<>())
|
||||||
|
.stream()
|
||||||
|
.sorted((t1, t2) -> t1.getIs_send().compareTo(t2.getIs_send()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
|
||||||
|
//如果分组后任务数量为1 下发单任务,分组后任务数量为2 下发双任务
|
||||||
|
if (tasks.size() == TASK_SIZE_1) {
|
||||||
|
TaskDto taskDto = tasks.get(0);
|
||||||
|
//判断任务是否需要立即下发AGV 不需要则是双任务,等待系统下发第二条任务后,走下发双任务的逻辑
|
||||||
|
if (StrUtil.equals(taskDto.getIs_send(), StatusEnum.NO_SEND.getCode())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction instDto = instructionService.createInstDtoByTask(taskDto);
|
||||||
|
|
||||||
|
try {
|
||||||
|
instructionService.autoCreateTwoInst(instDto, null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
taskDto.setRemark(e.getMessage());
|
||||||
|
taskService.updateByCodeFromCache(taskDto);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//创建指令后修改任务状态
|
||||||
|
taskDto.setTask_status(StatusEnum.TASK_RUNNING.getCode());
|
||||||
|
taskService.update(taskDto);
|
||||||
|
|
||||||
|
} else if (tasks.size() == TASK_SIZE_2) {
|
||||||
|
|
||||||
|
TaskDto taskDto1 = tasks.get(0);
|
||||||
|
TaskDto taskDto2 = tasks.get(1);
|
||||||
|
|
||||||
|
//关联编号一致 任务类型不一致 不生成任务
|
||||||
|
if (!taskDto1.getTask_type().equals(taskDto2.getTask_type())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction instDto1 = instructionService.createInstDtoByTask(taskDto1);
|
||||||
|
Instruction instDto2 = instructionService.createInstDtoByTask(taskDto2);
|
||||||
|
|
||||||
|
try {
|
||||||
|
instructionService.autoCreateTwoInst(instDto1, instDto2);
|
||||||
|
} catch (Exception e) {
|
||||||
|
taskDto1.setRemark(e.getMessage());
|
||||||
|
taskService.updateByCodeFromCache(taskDto1);
|
||||||
|
taskDto2.setRemark(e.getMessage());
|
||||||
|
taskService.updateByCodeFromCache(taskDto2);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//创建指令后修改任务状态
|
||||||
|
taskDto1.setTask_status(StatusEnum.TASK_RUNNING.getCode());
|
||||||
|
taskService.update(taskDto1);
|
||||||
|
taskDto2.setTask_status(StatusEnum.TASK_RUNNING.getCode());
|
||||||
|
taskService.update(taskDto2);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user