diff --git a/business/src/main/java/com/fizz/business/comm/iot/S7WriteClient.java b/business/src/main/java/com/fizz/business/comm/iot/S7WriteClient.java new file mode 100644 index 0000000..554124c --- /dev/null +++ b/business/src/main/java/com/fizz/business/comm/iot/S7WriteClient.java @@ -0,0 +1,48 @@ +package com.fizz.business.comm.iot; + +import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType; +import com.github.xingshuangs.iot.protocol.s7.service.S7PLC; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; + +import java.util.Locale; + +/** + * 基于 iot-communication 的 S7 写入客户端(仅用于写入)。 + */ +@Slf4j +@Component +@ConditionalOnProperty(prefix = "iot.communication", name = "enabled", havingValue = "true") +public class S7WriteClient { + + @Value("${iot.communication.s7.ip:127.0.0.1}") + private String ip; + + @Value("${iot.communication.s7.port:102}") + private int port; + + @Value("${iot.communication.s7.rack:0}") + private int rack; + + @Value("${iot.communication.s7.slot:1}") + private int slot; + + @Value("${iot.communication.s7.plc-type:S1200}") + private String plcType; + + public S7PLC newClient() { + EPlcType type = parsePlcType(plcType); + return new S7PLC(type, ip, port, rack, slot); + } + + private EPlcType parsePlcType(String value) { + try { + return EPlcType.valueOf(value.trim().toUpperCase(Locale.ROOT)); + } catch (Exception e) { + log.warn("未知 plc-type: {},回退到 S1200", value); + return EPlcType.S1200; + } + } +} diff --git a/business/src/main/java/com/fizz/business/controller/OpcDataController.java b/business/src/main/java/com/fizz/business/controller/OpcDataController.java index 29d6016..b3f01b7 100644 --- a/business/src/main/java/com/fizz/business/controller/OpcDataController.java +++ b/business/src/main/java/com/fizz/business/controller/OpcDataController.java @@ -22,7 +22,7 @@ import javax.validation.Valid; @RequiredArgsConstructor @RequestMapping("/api/opc/data") @Tag(name = "OPC 数据读写") -@ConditionalOnProperty(prefix = "kangaroohy.milo", name = "enabled", havingValue = "true") +@ConditionalOnProperty(prefix = "iot.communication", name = "enabled", havingValue = "true") @Anonymous public class OpcDataController { diff --git a/business/src/main/java/com/fizz/business/service/impl/OpcDataServiceImpl.java b/business/src/main/java/com/fizz/business/service/impl/OpcDataServiceImpl.java index db4d49f..8ba0ef1 100644 --- a/business/src/main/java/com/fizz/business/service/impl/OpcDataServiceImpl.java +++ b/business/src/main/java/com/fizz/business/service/impl/OpcDataServiceImpl.java @@ -1,52 +1,96 @@ package com.fizz.business.service.impl; -import com.fizz.business.comm.OPC.OpcMessageSend; +import com.fizz.business.comm.iot.S7WriteClient; import com.fizz.business.form.OpcBatchWriteDataForm; import com.fizz.business.form.OpcWriteDataForm; import com.fizz.business.service.OpcDataService; +import com.github.xingshuangs.iot.protocol.s7.service.S7PLC; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; -import java.util.Map; -import java.util.stream.Collectors; - /** * OPC 数据读写服务实现类 + * + * 说明: + * 1) 写入逻辑已切换为 iot-communication(S7) + * 2) 读取逻辑仍保留在原 OPC 体系(不在本类中) */ @Slf4j @Service @RequiredArgsConstructor -@ConditionalOnProperty(prefix = "kangaroohy.milo", name = "enabled", havingValue = "true") +@ConditionalOnProperty(prefix = "iot.communication", name = "enabled", havingValue = "true") public class OpcDataServiceImpl implements OpcDataService { - private final OpcMessageSend opcMessageSend; + private final S7WriteClient s7WriteClient; @Override public boolean writeData(OpcWriteDataForm form) { - try { - return opcMessageSend.writeDataByFieldName(form.getFieldName(), form.getValue()); + try (S7PLC s7PLC = s7WriteClient.newClient()) { + writeByGuessType(s7PLC, form.getFieldName(), form.getValue()); + return true; } catch (Exception e) { - log.error("写入 OPC 数据异常,fieldName={}, value={}", form.getFieldName(), form.getValue(), e); + log.error("写入 S7 数据异常,address={}, value={}", form.getFieldName(), form.getValue(), e); return false; } } @Override public boolean batchWriteData(OpcBatchWriteDataForm form) { - try { - Map fieldDataMap = form.getDataList().stream() - .collect(Collectors.toMap( - OpcWriteDataForm::getFieldName, - OpcWriteDataForm::getValue, - (v1, v2) -> v2 // 如果有重复的 key,保留后面的值 - )); - return opcMessageSend.batchWriteDataByFieldName(fieldDataMap); + try (S7PLC s7PLC = s7WriteClient.newClient()) { + for (OpcWriteDataForm item : form.getDataList()) { + writeByGuessType(s7PLC, item.getFieldName(), item.getValue()); + } + return true; } catch (Exception e) { - log.error("批量写入 OPC 数据异常", e); + log.error("批量写入 S7 数据异常", e); return false; } } -} + private void writeByGuessType(S7PLC s7PLC, String address, Object value) { + if (value == null) { + throw new IllegalArgumentException("写入值不能为空"); + } + if (address == null || address.trim().isEmpty()) { + throw new IllegalArgumentException("写入地址不能为空"); + } + + if (value instanceof Boolean) { + s7PLC.writeBoolean(address, (Boolean) value); + return; + } + if (value instanceof Byte) { + s7PLC.writeByte(address, (Byte) value); + return; + } + if (value instanceof Short) { + s7PLC.writeInt16(address, (Short) value); + return; + } + if (value instanceof Integer) { + s7PLC.writeInt32(address, (Integer) value); + return; + } + if (value instanceof Long) { + s7PLC.writeInt64(address, (Long) value); + return; + } + if (value instanceof Float) { + s7PLC.writeFloat32(address, (Float) value); + return; + } + if (value instanceof Double) { + s7PLC.writeFloat64(address, (Double) value); + return; + } + if (value instanceof byte[]) { + s7PLC.writeByte(address, (byte[]) value); + return; + } + + // 兜底按字符串写入 + s7PLC.writeString(address, String.valueOf(value)); + } +} diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index c810dbd..da36d1c 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -181,6 +181,18 @@ kangaroohy: min-idle: 2 initial-size: 3 +# iot-communication(S7)写入开关与连接参数 +# 注意:写入使用 iot-communication;读取逻辑仍沿用 OPC 现有体系 +iot: + communication: + enabled: true + s7: + ip: 127.0.0.1 + port: 102 + rack: 0 + slot: 1 + plc-type: S1200 + #kangaroohy: # milo: