package com.mes.plc.client.impl;
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType;
|
import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
|
import com.mes.device.entity.DeviceConfig;
|
import com.mes.plc.client.PlcClient;
|
import com.mes.service.PlcDynamicDataService;
|
import com.mes.s7.enhanced.EnhancedS7Serializer;
|
import lombok.extern.slf4j.Slf4j;
|
|
import java.util.Collections;
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.concurrent.ConcurrentHashMap;
|
|
/**
|
* S7协议PLC客户端实现
|
* <p>
|
* 基于现有的S7库实现PlcClient接口
|
* </p>
|
*
|
* @author huang
|
* @date 2025/12/19
|
*/
|
@Slf4j
|
public class S7PlcClient implements PlcClient {
|
|
// PLC类型
|
private final EPlcType plcType;
|
|
// PLC IP地址
|
private final String plcIp;
|
|
// PLC端口
|
private final int plcPort;
|
|
// 设备配置
|
private final DeviceConfig device;
|
|
// 模块名称
|
private final String moduleName;
|
|
// S7 PLC实例
|
private S7PLC s7Plc;
|
|
// S7序列化器
|
private EnhancedS7Serializer s7Serializer;
|
|
// 连接状态
|
private boolean connected = false;
|
|
// 超时时间(毫秒)
|
private int timeout = 5000;
|
|
// PLC类型映射
|
private static final Map<String, EPlcType> PLC_TYPE_MAP = new ConcurrentHashMap<>();
|
|
// PLC动态数据服务
|
private PlcDynamicDataService plcDynamicDataService;
|
|
/**
|
* 设置PLC动态数据服务
|
*
|
* @param plcDynamicDataService PLC动态数据服务实例
|
*/
|
public void setPlcDynamicDataService(PlcDynamicDataService plcDynamicDataService) {
|
this.plcDynamicDataService = plcDynamicDataService;
|
}
|
|
static {
|
// 初始化PLC类型映射
|
PLC_TYPE_MAP.put("S7_1200", EPlcType.S1200);
|
PLC_TYPE_MAP.put("S7_1500", EPlcType.S1500);
|
PLC_TYPE_MAP.put("S7_200", EPlcType.S200);
|
PLC_TYPE_MAP.put("S7_300", EPlcType.S300);
|
PLC_TYPE_MAP.put("S7_400", EPlcType.S400);
|
}
|
|
/**
|
* 构造函数
|
*
|
* @param device 设备配置
|
* @param s7Serializer S7序列化器
|
*/
|
public S7PlcClient(DeviceConfig device, EnhancedS7Serializer s7Serializer) {
|
this.device = device;
|
this.plcIp = device.getPlcIp();
|
this.plcPort = device.getPlcPort() != null ? device.getPlcPort() : 102;
|
this.moduleName = device.getModuleName() != null ? device.getModuleName() : "DB1";
|
this.s7Serializer = s7Serializer;
|
|
// 解析PLC类型
|
String plcTypeValue = device.getPlcType();
|
this.plcType = PLC_TYPE_MAP.getOrDefault(plcTypeValue, EPlcType.S1200);
|
}
|
|
@Override
|
public boolean connect() {
|
try {
|
if (s7Plc != null && isConnected()) {
|
return true;
|
}
|
|
// 创建S7PLC实例
|
this.s7Plc = new S7PLC(this.plcType, this.plcIp, this.plcPort);
|
|
|
// 连接PLC
|
this.s7Plc.connect();
|
this.connected = true;
|
log.info("S7 PLC连接成功: {}:{},类型: {}", this.plcIp, this.plcPort, this.plcType);
|
return true;
|
} catch (Exception e) {
|
log.error("S7 PLC连接失败: {}:{}", this.plcIp, this.plcPort, e);
|
this.connected = false;
|
return false;
|
}
|
}
|
|
@Override
|
public void disconnect() {
|
try {
|
if (this.s7Plc != null) {
|
|
log.info("S7 PLC断开连接: {}:{}", this.plcIp, this.plcPort);
|
}
|
} catch (Exception e) {
|
log.error("S7 PLC断开连接失败: {}:{}", this.plcIp, this.plcPort, e);
|
} finally {
|
this.connected = false;
|
this.s7Plc = null;
|
}
|
}
|
|
@Override
|
public Map<String, Object> readAllData() {
|
if (!isConnected() && !connect()) {
|
log.error("S7 PLC未连接,无法读取数据: {}:{}", this.plcIp, this.plcPort);
|
return Collections.emptyMap();
|
}
|
|
try {
|
if (this.plcDynamicDataService == null) {
|
log.error("PLC动态数据服务未初始化,无法读取数据: {}:{}", this.plcIp, this.plcPort);
|
return Collections.emptyMap();
|
}
|
|
// 使用PlcDynamicDataService读取所有PLC数据
|
Map<String, Object> data = this.plcDynamicDataService.readAllPlcData(this.device, this.s7Serializer);
|
if (data == null) {
|
log.warn("PLC动态数据服务返回空数据: {}:{}", this.plcIp, this.plcPort);
|
return new HashMap<>();
|
}
|
|
log.info("S7 PLC读取所有数据成功: {}:{}, dataSize={}", this.plcIp, this.plcPort, data.size());
|
return data;
|
} catch (Exception e) {
|
log.error("S7 PLC读取所有数据失败: {}:{}", this.plcIp, this.plcPort, e);
|
this.connected = false;
|
return Collections.emptyMap();
|
}
|
}
|
|
@Override
|
public Map<String, Object> readData(String... fields) {
|
if (!isConnected() && !connect()) {
|
log.error("S7 PLC未连接,无法读取数据: {}:{}", this.plcIp, this.plcPort);
|
return Collections.emptyMap();
|
}
|
|
try {
|
if (this.plcDynamicDataService == null) {
|
log.error("PLC动态数据服务未初始化,无法读取数据: {}:{}", this.plcIp, this.plcPort);
|
return Collections.emptyMap();
|
}
|
|
if (fields == null || fields.length == 0) {
|
return readAllData();
|
}
|
|
// 使用PlcDynamicDataService读取指定字段PLC数据
|
Map<String, Object> data = this.plcDynamicDataService.readPlcData(this.device, java.util.Arrays.asList(fields), this.s7Serializer);
|
if (data == null) {
|
log.warn("PLC动态数据服务返回空数据: {}:{}", this.plcIp, this.plcPort);
|
return new HashMap<>();
|
}
|
|
log.info("S7 PLC读取指定字段数据成功: {}:{}, fields={}", this.plcIp, this.plcPort, java.util.Arrays.toString(fields));
|
return data;
|
} catch (Exception e) {
|
log.error("S7 PLC读取数据失败: {}:{}", this.plcIp, this.plcPort, e);
|
this.connected = false;
|
return Collections.emptyMap();
|
}
|
}
|
|
@Override
|
public boolean writeData(Map<String, Object> data) {
|
if (!isConnected() && !connect()) {
|
log.error("S7 PLC未连接,无法写入数据: {}:{}", this.plcIp, this.plcPort);
|
return false;
|
}
|
|
try {
|
if (this.plcDynamicDataService == null) {
|
log.error("PLC动态数据服务未初始化,无法写入数据: {}:{}", this.plcIp, this.plcPort);
|
return false;
|
}
|
|
if (data == null || data.isEmpty()) {
|
log.warn("写入数据为空,跳过操作: {}:{}", this.plcIp, this.plcPort);
|
return true;
|
}
|
|
// 使用PlcDynamicDataService写入PLC数据
|
this.plcDynamicDataService.writePlcData(this.device, data, this.s7Serializer);
|
log.info("S7 PLC写入数据成功: {}:{}, fields={}", this.plcIp, this.plcPort, data.keySet());
|
return true;
|
} catch (Exception e) {
|
log.error("S7 PLC写入数据失败: {}:{}", this.plcIp, this.plcPort, e);
|
this.connected = false;
|
return false;
|
}
|
}
|
|
@Override
|
public boolean isConnected() {
|
try {
|
// S7PLC不支持直接检查连接状态,使用内部标志
|
return this.connected && this.s7Plc != null;
|
} catch (Exception e) {
|
this.connected = false;
|
return false;
|
}
|
}
|
|
@Override
|
public String getPlcType() {
|
return this.plcType.name();
|
}
|
|
@Override
|
public int getTimeout() {
|
return this.timeout;
|
}
|
|
@Override
|
public void setTimeout(int timeout) {
|
this.timeout = timeout;
|
|
}
|
}
|