| | |
| | | package com.mes.service.impl; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.fasterxml.jackson.core.type.TypeReference; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import com.github.xingshuangs.iot.common.enums.EDataType; |
| | | import com.github.xingshuangs.iot.protocol.s7.serializer.S7Parameter; |
| | | import com.mes.device.entity.DeviceConfig; |
| | | import com.mes.device.util.ConfigJsonHelper; |
| | | import com.mes.entity.PlcAddress; |
| | | import com.mes.s7.enhanced.EnhancedS7Serializer; |
| | | import com.mes.service.PlcDynamicDataService; |
| | |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | |
| | | @Slf4j |
| | | @Service |
| | | public class PlcDynamicDataServiceImpl implements PlcDynamicDataService { |
| | | |
| | | private final ObjectMapper objectMapper = new ObjectMapper(); |
| | | private static final TypeReference<Map<String, Object>> MAP_TYPE = new TypeReference<Map<String, Object>>() {}; |
| | | |
| | | /** |
| | | * 根据PlcAddress配置和字段名称读取PLC数据 |
| | |
| | | |
| | | return resultMap; |
| | | } catch (Exception e) { |
| | | log.error("读取PLC数据失败,请检查:1.PLC IP地址是否正确[{}] 2.PLC设备是否在线 3.网络连接是否正常,module: {}, 详细错误: {}", |
| | | config.getPlcIp(), config.getModule(), e.getMessage(), e); |
| | | log.error("读取PLC数据失败,请检查:1.PLC IP地址是否正确[{}] 2.PLC设备是否在线 3.网络连接是否正常,详细错误: {}", |
| | | config.getPlcIp(), e.getMessage(), e); |
| | | return new HashMap<>(); |
| | | } |
| | | } |
| | |
| | | // 写入PLC |
| | | s7Serializer.write(parameters); |
| | | } catch (Exception e) { |
| | | log.error("写入PLC数据失败,请检查:1.PLC IP地址是否正确[{}] 2.PLC设备是否在线 3.网络连接是否正常,module: {}, 详细错误: {}", |
| | | config.getPlcIp(), config.getModule(), e.getMessage(), e); |
| | | log.error("写入PLC数据失败,请检查:1.PLC IP地址是否正确[{}] 2.PLC设备是否在线 3.网络连接是否正常,详细错误: {}", |
| | | config.getPlcIp(), e.getMessage(), e); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | return parameters; |
| | | } |
| | | |
| | | /** |
| | | * 从DeviceConfig中提取地址映射配置 |
| | | * |
| | | * @param device 设备配置 |
| | | * @return 地址映射JSON字符串 |
| | | */ |
| | | private String extractAddressMapping(DeviceConfig device) { |
| | | // configJson 现在仅存放字段地址映射(数组形式) |
| | | Map<String, Object> configParams = ConfigJsonHelper.parseToMap(device.getConfigJson(), objectMapper); |
| | | if (!configParams.isEmpty()) { |
| | | try { |
| | | return objectMapper.writeValueAsString(configParams); |
| | | } catch (Exception e) { |
| | | log.warn("序列化configJson地址映射失败, deviceId={}", device.getId(), e); |
| | | } |
| | | } |
| | | |
| | | // 其次从extraParams中获取(兼容旧结构) |
| | | Map<String, Object> extraParams = parseExtraParams(device); |
| | | Object addressMapping = extraParams.get("addressMapping"); |
| | | if (addressMapping != null) { |
| | | if (addressMapping instanceof String) { |
| | | return (String) addressMapping; |
| | | } else { |
| | | try { |
| | | return objectMapper.writeValueAsString(addressMapping); |
| | | } catch (Exception e) { |
| | | log.warn("序列化extraParams.addressMapping失败, deviceId={}", device.getId(), e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | throw new IllegalArgumentException("设备配置中未找到addressMapping, deviceId=" + device.getId()); |
| | | } |
| | | |
| | | /** |
| | | * 从DeviceConfig中提取dbArea |
| | | * |
| | | * @param device 设备配置 |
| | | * @return dbArea |
| | | */ |
| | | private String extractDbArea(DeviceConfig device) { |
| | | // 从extraParams.plcConfig中获取(新结构) |
| | | Map<String, Object> plcConfig = getPlcConfig(device); |
| | | Object dbArea = plcConfig.get("dbArea"); |
| | | if (dbArea != null) { |
| | | return String.valueOf(dbArea); |
| | | } |
| | | |
| | | // 兼容旧结构:extraParams根节点 |
| | | Map<String, Object> extraParams = parseExtraParams(device); |
| | | Object legacyDbArea = extraParams.get("dbArea"); |
| | | if (legacyDbArea != null) { |
| | | return String.valueOf(legacyDbArea); |
| | | } |
| | | |
| | | // 默认值 |
| | | return "DB12"; |
| | | } |
| | | |
| | | /** |
| | | * 从DeviceConfig中提取beginIndex |
| | | * |
| | | * @param device 设备配置 |
| | | * @return beginIndex |
| | | */ |
| | | private int extractBeginIndex(DeviceConfig device) { |
| | | // 从extraParams.plcConfig中获取 |
| | | Map<String, Object> plcConfig = getPlcConfig(device); |
| | | Object beginIndex = plcConfig.get("beginIndex"); |
| | | if (beginIndex != null) { |
| | | return parseInteger(beginIndex); |
| | | } |
| | | |
| | | // 兼容旧结构:extraParams根节点 |
| | | Map<String, Object> extraParams = parseExtraParams(device); |
| | | Object legacyBeginIndex = extraParams.get("beginIndex"); |
| | | if (legacyBeginIndex != null) { |
| | | return parseInteger(legacyBeginIndex); |
| | | } |
| | | |
| | | // 默认值 |
| | | return 0; |
| | | } |
| | | |
| | | private Map<String, Object> parseExtraParams(DeviceConfig device) { |
| | | if (device.getExtraParams() == null || device.getExtraParams().trim().isEmpty()) { |
| | | return Collections.emptyMap(); |
| | | } |
| | | try { |
| | | return objectMapper.readValue(device.getExtraParams(), MAP_TYPE); |
| | | } catch (Exception e) { |
| | | log.warn("解析设备extraParams失败, deviceId={}", device.getId(), e); |
| | | return Collections.emptyMap(); |
| | | } |
| | | } |
| | | |
| | | @SuppressWarnings("unchecked") |
| | | private Map<String, Object> getPlcConfig(DeviceConfig device) { |
| | | Map<String, Object> extraParams = parseExtraParams(device); |
| | | Object plcConfig = extraParams.get("plcConfig"); |
| | | if (plcConfig instanceof Map) { |
| | | return (Map<String, Object>) plcConfig; |
| | | } |
| | | if (plcConfig instanceof String) { |
| | | try { |
| | | return objectMapper.readValue((String) plcConfig, MAP_TYPE); |
| | | } catch (Exception e) { |
| | | log.warn("解析extraParams.plcConfig失败, deviceId={}", device.getId(), e); |
| | | } |
| | | } |
| | | return Collections.emptyMap(); |
| | | } |
| | | |
| | | private int parseInteger(Object value) { |
| | | if (value instanceof Number) { |
| | | return ((Number) value).intValue(); |
| | | } |
| | | try { |
| | | return Integer.parseInt(String.valueOf(value)); |
| | | } catch (NumberFormatException ex) { |
| | | log.warn("无法解析整数值: {}", value); |
| | | return 0; |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public Map<String, Object> readPlcData(DeviceConfig device, List<String> fieldNames, EnhancedS7Serializer s7Serializer) { |
| | | if (device == null) { |
| | | throw new IllegalArgumentException("设备配置不能为空"); |
| | | } |
| | | |
| | | String addressMapping = extractAddressMapping(device); |
| | | if (addressMapping == null || addressMapping.isEmpty()) { |
| | | throw new IllegalArgumentException("设备配置中addressMapping不能为空"); |
| | | } |
| | | |
| | | try { |
| | | // 解析addressMapping JSON配置 |
| | | JSONObject addressMappingObj = JSONObject.parseObject(addressMapping); |
| | | |
| | | // 构建S7Parameter列表 |
| | | String dbArea = extractDbArea(device); |
| | | List<S7Parameter> parameters = buildS7ParametersForDevice(device, dbArea, addressMappingObj, fieldNames); |
| | | |
| | | // 从PLC读取数据 |
| | | List<S7Parameter> results = s7Serializer.read(parameters); |
| | | |
| | | // 将结果转换为Map |
| | | Map<String, Object> resultMap = new HashMap<>(); |
| | | for (int i = 0; i < fieldNames.size() && i < results.size(); i++) { |
| | | String fieldName = fieldNames.get(i); |
| | | Object value = results.get(i).getValue(); |
| | | resultMap.put(fieldName, value); |
| | | } |
| | | |
| | | return resultMap; |
| | | } catch (Exception e) { |
| | | log.error("读取PLC数据失败,请检查:1.PLC IP地址是否正确[{}] 2.PLC设备是否在线 3.网络连接是否正常,deviceId: {}, 详细错误: {}", |
| | | device.getPlcIp(), device.getId(), e.getMessage(), e); |
| | | return new HashMap<>(); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void writePlcData(DeviceConfig device, Map<String, Object> dataMap, EnhancedS7Serializer s7Serializer) { |
| | | if (device == null) { |
| | | throw new IllegalArgumentException("设备配置不能为空"); |
| | | } |
| | | |
| | | String addressMapping = extractAddressMapping(device); |
| | | if (addressMapping == null || addressMapping.isEmpty()) { |
| | | throw new IllegalArgumentException("设备配置中addressMapping不能为空"); |
| | | } |
| | | |
| | | try { |
| | | // 解析addressMapping JSON配置 |
| | | JSONObject addressMappingObj = JSONObject.parseObject(addressMapping); |
| | | |
| | | // 构建S7Parameter列表,并填充值 |
| | | String dbArea = extractDbArea(device); |
| | | List<S7Parameter> parameters = buildS7ParametersWithValuesForDevice(device, dbArea, addressMappingObj, dataMap); |
| | | |
| | | // 写入PLC |
| | | s7Serializer.write(parameters); |
| | | } catch (Exception e) { |
| | | log.error("写入PLC数据失败,请检查:1.PLC IP地址是否正确[{}] 2.PLC设备是否在线 3.网络连接是否正常,deviceId: {}, 详细错误: {}", |
| | | device.getPlcIp(), device.getId(), e.getMessage(), e); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public Map<String, Object> readAllPlcData(DeviceConfig device, EnhancedS7Serializer s7Serializer) { |
| | | if (device == null) { |
| | | throw new IllegalArgumentException("设备配置不能为空"); |
| | | } |
| | | |
| | | String addressMapping = extractAddressMapping(device); |
| | | if (addressMapping == null || addressMapping.isEmpty()) { |
| | | throw new IllegalArgumentException("设备配置中addressMapping不能为空"); |
| | | } |
| | | |
| | | // 获取所有字段名 |
| | | JSONObject addressMappingObj = JSONObject.parseObject(addressMapping); |
| | | List<String> allFields = new ArrayList<>(addressMappingObj.keySet()); |
| | | |
| | | // 读取所有字段 |
| | | return readPlcData(device, allFields, s7Serializer); |
| | | } |
| | | |
| | | @Override |
| | | public Object readPlcField(DeviceConfig device, String fieldName, EnhancedS7Serializer s7Serializer) { |
| | | List<String> fields = new ArrayList<>(); |
| | | fields.add(fieldName); |
| | | |
| | | Map<String, Object> result = readPlcData(device, fields, s7Serializer); |
| | | return result.get(fieldName); |
| | | } |
| | | |
| | | @Override |
| | | public void writePlcField(DeviceConfig device, String fieldName, Object value, EnhancedS7Serializer s7Serializer) { |
| | | Map<String, Object> dataMap = new HashMap<>(); |
| | | dataMap.put(fieldName, value); |
| | | |
| | | writePlcData(device, dataMap, s7Serializer); |
| | | } |
| | | |
| | | /** |
| | | * 构建S7Parameter列表(不包含值)- 基于DeviceConfig |
| | | */ |
| | | private List<S7Parameter> buildS7ParametersForDevice(DeviceConfig device, String dbArea, JSONObject addressMapping, List<String> fieldNames) { |
| | | List<S7Parameter> parameters = new ArrayList<>(); |
| | | |
| | | for (String fieldName : fieldNames) { |
| | | if (!addressMapping.containsKey(fieldName)) { |
| | | log.warn("字段 {} 在addressMapping中不存在,跳过", fieldName); |
| | | continue; |
| | | } |
| | | |
| | | // 获取字段的偏移地址 |
| | | int offset = addressMapping.getInteger(fieldName); |
| | | |
| | | // 构建完整地址:dbArea + offset(如:DB12.2) |
| | | String fullAddress = dbArea + "." + offset; |
| | | |
| | | // 创建S7Parameter,默认使用UINT16类型(16位无符号整数) |
| | | S7Parameter parameter = new S7Parameter(fullAddress, EDataType.UINT16, 1); |
| | | parameters.add(parameter); |
| | | } |
| | | |
| | | return parameters; |
| | | } |
| | | |
| | | /** |
| | | * 构建S7Parameter列表(包含值)- 基于DeviceConfig |
| | | */ |
| | | private List<S7Parameter> buildS7ParametersWithValuesForDevice(DeviceConfig device, String dbArea, JSONObject addressMapping, Map<String, Object> dataMap) { |
| | | List<S7Parameter> parameters = new ArrayList<>(); |
| | | |
| | | for (Map.Entry<String, Object> entry : dataMap.entrySet()) { |
| | | String fieldName = entry.getKey(); |
| | | Object value = entry.getValue(); |
| | | |
| | | if (!addressMapping.containsKey(fieldName)) { |
| | | log.warn("字段 {} 在addressMapping中不存在,跳过", fieldName); |
| | | continue; |
| | | } |
| | | |
| | | // 获取字段的偏移地址 |
| | | int offset = addressMapping.getInteger(fieldName); |
| | | |
| | | // 构建完整地址 |
| | | String fullAddress = dbArea + "." + offset; |
| | | |
| | | // 创建S7Parameter,设置值 |
| | | S7Parameter parameter = new S7Parameter(fullAddress, EDataType.UINT16, 1); |
| | | parameter.setValue(value); |
| | | parameters.add(parameter); |
| | | } |
| | | |
| | | return parameters; |
| | | } |
| | | } |