package com.mes.interaction.impl;
|
|
import com.mes.device.entity.DeviceConfig;
|
import com.mes.interaction.BaseDeviceLogicHandler;
|
import com.mes.device.service.DevicePlcOperationService;
|
import com.mes.device.vo.DevicePlcVO;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.stereotype.Component;
|
|
import java.util.ArrayList;
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Objects;
|
|
/**
|
* 上大车设备逻辑处理器
|
*
|
* @author mes
|
* @since 2025-01-XX
|
*/
|
@Slf4j
|
@Component
|
public class LoadVehicleLogicHandler extends BaseDeviceLogicHandler {
|
|
public LoadVehicleLogicHandler(DevicePlcOperationService devicePlcOperationService) {
|
super(devicePlcOperationService);
|
}
|
|
@Override
|
public String getDeviceType() {
|
return DeviceConfig.DeviceType.LOAD_VEHICLE;
|
}
|
|
@Override
|
protected DevicePlcVO.OperationResult doExecute(
|
DeviceConfig deviceConfig,
|
String operation,
|
Map<String, Object> params,
|
Map<String, Object> logicParams) {
|
|
log.info("执行上大车设备操作: deviceId={}, operation={}", deviceConfig.getId(), operation);
|
|
switch (operation) {
|
case "feedGlass":
|
return handleFeedGlass(deviceConfig, params, logicParams);
|
case "triggerRequest":
|
return handleTriggerRequest(deviceConfig, params, logicParams);
|
case "triggerReport":
|
return handleTriggerReport(deviceConfig, params, logicParams);
|
case "reset":
|
return handleReset(deviceConfig, params, logicParams);
|
default:
|
log.warn("不支持的操作类型: {}", operation);
|
return DevicePlcVO.OperationResult.builder()
|
.success(false)
|
.message("不支持的操作: " + operation)
|
.build();
|
}
|
}
|
|
/**
|
* 处理玻璃上料操作
|
*/
|
private DevicePlcVO.OperationResult handleFeedGlass(
|
DeviceConfig deviceConfig,
|
Map<String, Object> params,
|
Map<String, Object> logicParams) {
|
|
// 从逻辑参数中获取配置(从 extraParams.deviceLogic 读取)
|
Integer vehicleCapacity = getLogicParam(logicParams, "vehicleCapacity", 6000);
|
Integer glassIntervalMs = getLogicParam(logicParams, "glassIntervalMs", 1000);
|
Boolean autoFeed = getLogicParam(logicParams, "autoFeed", true);
|
Integer maxRetryCount = getLogicParam(logicParams, "maxRetryCount", 5);
|
|
// 从运行时参数中获取数据(从接口调用时传入)
|
List<GlassInfo> glassInfos = extractGlassInfos(params);
|
if (glassInfos.isEmpty()) {
|
return DevicePlcVO.OperationResult.builder()
|
.success(false)
|
.message("未提供有效的玻璃信息")
|
.build();
|
}
|
|
String positionCode = (String) params.get("positionCode");
|
Integer positionValue = (Integer) params.get("positionValue");
|
Boolean triggerRequest = (Boolean) params.getOrDefault("triggerRequest", autoFeed);
|
|
List<GlassInfo> plannedGlasses = planGlassLoading(glassInfos, vehicleCapacity,
|
getLogicParam(logicParams, "defaultGlassLength", 2000));
|
if (plannedGlasses.isEmpty()) {
|
return DevicePlcVO.OperationResult.builder()
|
.success(false)
|
.message("当前玻璃尺寸超出车辆容量,无法装载")
|
.build();
|
}
|
|
// 构建写入数据
|
Map<String, Object> payload = new HashMap<>();
|
|
// 写入玻璃ID
|
int plcSlots = Math.min(plannedGlasses.size(), 6);
|
for (int i = 0; i < plcSlots; i++) {
|
String fieldName = "plcGlassId" + (i + 1);
|
payload.put(fieldName, plannedGlasses.get(i).getGlassId());
|
}
|
payload.put("plcGlassCount", plcSlots);
|
|
// 写入位置信息
|
if (positionValue != null) {
|
payload.put("inPosition", positionValue);
|
} else if (positionCode != null) {
|
// 从位置映射中获取位置值
|
@SuppressWarnings("unchecked")
|
Map<String, Integer> positionMapping = getLogicParam(logicParams, "positionMapping", new HashMap<>());
|
Integer mappedValue = positionMapping.get(positionCode);
|
if (mappedValue != null) {
|
payload.put("inPosition", mappedValue);
|
}
|
}
|
|
// 自动触发请求字
|
if (triggerRequest != null && triggerRequest) {
|
payload.put("plcRequest", 1);
|
}
|
|
String operationName = "上大车-玻璃上料";
|
if (positionCode != null) {
|
operationName += "(" + positionCode + ")";
|
}
|
|
log.info("上大车玻璃上料: deviceId={}, glassCount={}, position={}, plannedGlassIds={}",
|
deviceConfig.getId(), plcSlots, positionCode, plannedGlasses);
|
|
if (glassIntervalMs != null && glassIntervalMs > 0) {
|
try {
|
Thread.sleep(glassIntervalMs);
|
} catch (InterruptedException e) {
|
Thread.currentThread().interrupt();
|
}
|
}
|
|
return devicePlcOperationService.writeFields(deviceConfig.getId(), payload, operationName);
|
}
|
|
/**
|
* 处理触发请求操作
|
*/
|
private DevicePlcVO.OperationResult handleTriggerRequest(
|
DeviceConfig deviceConfig,
|
Map<String, Object> params,
|
Map<String, Object> logicParams) {
|
|
Map<String, Object> payload = new HashMap<>();
|
payload.put("plcRequest", 1);
|
|
log.info("上大车触发请求: deviceId={}", deviceConfig.getId());
|
return devicePlcOperationService.writeFields(
|
deviceConfig.getId(),
|
payload,
|
"上大车-触发请求"
|
);
|
}
|
|
/**
|
* 处理触发汇报操作
|
*/
|
private DevicePlcVO.OperationResult handleTriggerReport(
|
DeviceConfig deviceConfig,
|
Map<String, Object> params,
|
Map<String, Object> logicParams) {
|
|
Map<String, Object> payload = new HashMap<>();
|
payload.put("plcReport", 1);
|
|
log.info("上大车触发汇报: deviceId={}", deviceConfig.getId());
|
return devicePlcOperationService.writeFields(
|
deviceConfig.getId(),
|
payload,
|
"上大车-触发汇报"
|
);
|
}
|
|
/**
|
* 处理重置操作
|
*/
|
private DevicePlcVO.OperationResult handleReset(
|
DeviceConfig deviceConfig,
|
Map<String, Object> params,
|
Map<String, Object> logicParams) {
|
|
Map<String, Object> payload = new HashMap<>();
|
payload.put("plcRequest", 0);
|
payload.put("plcReport", 0);
|
|
log.info("上大车重置: deviceId={}", deviceConfig.getId());
|
return devicePlcOperationService.writeFields(
|
deviceConfig.getId(),
|
payload,
|
"上大车-重置"
|
);
|
}
|
|
@Override
|
public String validateLogicParams(DeviceConfig deviceConfig) {
|
Map<String, Object> logicParams = parseLogicParams(deviceConfig);
|
|
// 验证必填参数
|
Integer vehicleCapacity = getLogicParam(logicParams, "vehicleCapacity", null);
|
if (vehicleCapacity == null || vehicleCapacity <= 0) {
|
return "车辆容量(vehicleCapacity)必须大于0";
|
}
|
|
Integer glassIntervalMs = getLogicParam(logicParams, "glassIntervalMs", null);
|
if (glassIntervalMs != null && glassIntervalMs < 0) {
|
return "玻璃间隔时间(glassIntervalMs)不能为负数";
|
}
|
|
return null; // 验证通过
|
}
|
|
@Override
|
public String getDefaultLogicParams() {
|
Map<String, Object> defaultParams = new HashMap<>();
|
defaultParams.put("vehicleCapacity", 6000);
|
defaultParams.put("glassIntervalMs", 1000);
|
defaultParams.put("autoFeed", true);
|
defaultParams.put("maxRetryCount", 5);
|
defaultParams.put("defaultGlassLength", 2000);
|
|
Map<String, Integer> positionMapping = new HashMap<>();
|
positionMapping.put("POS1", 1);
|
positionMapping.put("POS2", 2);
|
defaultParams.put("positionMapping", positionMapping);
|
|
try {
|
return objectMapper.writeValueAsString(defaultParams);
|
} catch (Exception e) {
|
log.error("生成默认逻辑参数失败", e);
|
return "{}";
|
}
|
}
|
|
@SuppressWarnings("unchecked")
|
private List<GlassInfo> extractGlassInfos(Map<String, Object> params) {
|
List<GlassInfo> result = new ArrayList<>();
|
Object rawGlassInfos = params.get("glassInfos");
|
if (rawGlassInfos instanceof List) {
|
List<?> list = (List<?>) rawGlassInfos;
|
for (Object item : list) {
|
GlassInfo info = convertToGlassInfo(item);
|
if (info != null) {
|
result.add(info);
|
}
|
}
|
}
|
|
if (result.isEmpty()) {
|
List<String> glassIds = (List<String>) params.get("glassIds");
|
if (glassIds != null) {
|
for (String glassId : glassIds) {
|
result.add(new GlassInfo(glassId, null));
|
}
|
}
|
}
|
return result;
|
}
|
|
private GlassInfo convertToGlassInfo(Object source) {
|
if (source instanceof GlassInfo) {
|
return (GlassInfo) source;
|
}
|
if (source instanceof Map) {
|
Map<?, ?> map = (Map<?, ?>) source;
|
Object id = map.get("glassId");
|
if (id == null) {
|
id = map.get("id");
|
}
|
if (id == null) {
|
return null;
|
}
|
Integer length = parseLength(map.get("length"));
|
if (length == null) {
|
length = parseLength(map.get("size"));
|
}
|
return new GlassInfo(String.valueOf(id), length);
|
}
|
if (source instanceof String) {
|
return new GlassInfo((String) source, null);
|
}
|
return null;
|
}
|
|
private Integer parseLength(Object value) {
|
if (value instanceof Number) {
|
return ((Number) value).intValue();
|
}
|
if (value instanceof String) {
|
try {
|
return Integer.parseInt((String) value);
|
} catch (NumberFormatException ignored) {
|
}
|
}
|
return null;
|
}
|
|
private List<GlassInfo> planGlassLoading(List<GlassInfo> source,
|
int vehicleCapacity,
|
Integer defaultGlassLength) {
|
List<GlassInfo> planned = new ArrayList<>();
|
int usedLength = 0;
|
int capacity = Math.max(vehicleCapacity, 1);
|
int fallbackLength = defaultGlassLength != null && defaultGlassLength > 0 ? defaultGlassLength : 2000;
|
|
for (GlassInfo info : source) {
|
int length = info.getLength() != null && info.getLength() > 0 ? info.getLength() : fallbackLength;
|
if (planned.isEmpty()) {
|
planned.add(info.withLength(length));
|
usedLength = length;
|
continue;
|
}
|
if (usedLength + length <= capacity) {
|
planned.add(info.withLength(length));
|
usedLength += length;
|
} else {
|
break;
|
}
|
}
|
return planned;
|
}
|
|
private static class GlassInfo {
|
private final String glassId;
|
private final Integer length;
|
|
GlassInfo(String glassId, Integer length) {
|
this.glassId = glassId;
|
this.length = length;
|
}
|
|
public String getGlassId() {
|
return glassId;
|
}
|
|
public Integer getLength() {
|
return length;
|
}
|
|
public GlassInfo withLength(Integer newLength) {
|
return new GlassInfo(this.glassId, newLength);
|
}
|
|
@Override
|
public String toString() {
|
return glassId;
|
}
|
|
@Override
|
public int hashCode() {
|
return Objects.hash(glassId, length);
|
}
|
|
@Override
|
public boolean equals(Object obj) {
|
if (this == obj) return true;
|
if (obj == null || getClass() != obj.getClass()) return false;
|
GlassInfo other = (GlassInfo) obj;
|
return Objects.equals(glassId, other.glassId) && Objects.equals(length, other.length);
|
}
|
}
|
}
|