概要
- 轉(zhuǎn)載地址
- 通過(guò)后端集成ModbusTCP協(xié)議,主動(dòng)請(qǐng)求從站獲取數(shù)據(jù)。
- 因甲方方案調(diào)整涕癣,此代碼最終未采用,故也未進(jìn)行更多的處理與優(yōu)化前标。
什么是Modbus TCP
如何集成Modbus TCP MASTER
仿真機(jī)下載地址 仿真機(jī)有主站和從站 需要模擬從站 下載 Modbus Slave 激活碼 5455415451475662
添加依賴
implementation 'com.digitalpetri.modbus:modbus-master-tcp:1.1.0'
- 貼代碼
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.ExecutionException;
@RestController
@RequestMapping("/modbus")
public class ModbusApi {
private static final Logger LOGGER = LoggerFactory.getLogger(ModbusApi.class);
@Autowired
private ModbusService modbusService;
@ResponseBody
@GetMapping
public void get(int address, int unitId, ModbusEunm modbusEunm, int typeId) throws ExecutionException, InterruptedException {
modbusService.get(address, unitId, modbusEunm, typeId);
}
}
import com.syxp.dlsesp.base.BaseService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.ExecutionException;
@Service
public class ModbusService extends BaseService<ModbusEntity> {
private static final Logger LOGGER = LoggerFactory.getLogger(ModbusService.class);
@Autowired
private ModbusMasterTCP modbusMasterTCP;
public void get(int address, int unitId, ModbusEunm modbusEunm, int typeId) throws ExecutionException, InterruptedException {
Number number;
switch (modbusEunm) {
case COILS:
Boolean coils = modbusMasterTCP.readCoils(address, unitId, typeId);
number = coils ? 1 : 0;
break;
case DISCRETE_INPUTS:
Boolean discreteInputs = modbusMasterTCP.readDiscreteInputs(address, unitId, typeId);
number = discreteInputs ? 1 : 0;
break;
case HOLDING_REGISTERS:
number = modbusMasterTCP.readHoldingRegisters(address, unitId, typeId);
break;
case INPUT_REGISTERS:
number = modbusMasterTCP.readInputRegisters(address, unitId, typeId);
break;
default:
number = -1;
}
ModbusEntity modbusEntity = new ModbusEntity();
modbusEntity.setAddress(address);
modbusEntity.setfId(modbusEunm.getCode());
modbusEntity.setsId(unitId);
modbusEntity.setData(number.doubleValue());
this.save(modbusEntity);
LOGGER.info(number.toString());
}
}
import com.digitalpetri.modbus.codec.Modbus;
import com.digitalpetri.modbus.master.ModbusTcpMaster;
import com.digitalpetri.modbus.master.ModbusTcpMasterConfig;
import com.digitalpetri.modbus.requests.ReadCoilsRequest;
import com.digitalpetri.modbus.requests.ReadDiscreteInputsRequest;
import com.digitalpetri.modbus.requests.ReadHoldingRegistersRequest;
import com.digitalpetri.modbus.requests.ReadInputRegistersRequest;
import com.digitalpetri.modbus.responses.ReadCoilsResponse;
import com.digitalpetri.modbus.responses.ReadDiscreteInputsResponse;
import com.digitalpetri.modbus.responses.ReadHoldingRegistersResponse;
import com.digitalpetri.modbus.responses.ReadInputRegistersResponse;
import com.serotonin.modbus4j.code.DataType;
import io.netty.buffer.ByteBuf;
import io.netty.util.ReferenceCountUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@Component
public class ModbusMasterTCP {
public static String address;
public static int port;
public String getAddress() {
return address;
}
@Value("${modbusAddress}")
public void setAddress(String address) {
ModbusMasterTCP.address = address;
}
public int getPort() {
return port;
}
@Value("${modbusPort}")
public void setPort(int port) {
ModbusMasterTCP.port = port;
}
static ModbusTcpMaster master;
/**
* 獲取TCP協(xié)議的Master
*
* @return
*/
@Bean
public void initModbusTcpMaster() {
if (master == null) {
// 創(chuàng)建配置
ModbusTcpMasterConfig config = new ModbusTcpMasterConfig.Builder(ModbusMasterTCP.address).setPort(ModbusMasterTCP.port).build();
master = new ModbusTcpMaster(config);
}
}
/***
* 釋放資源
*/
public void release() {
if (master != null) {
master.disconnect();
}
Modbus.releaseSharedResources();
}
/**
* 讀取Coils開關(guān)量
*
* @param address 寄存器開始地址
* @param unitId ID
* @return 讀取值
* @throws InterruptedException 異常
* @throws ExecutionException 異常
*/
public Boolean readCoils(int address, int unitId, int typeId)
throws InterruptedException, ExecutionException {
Boolean result = null;
CompletableFuture<ReadCoilsResponse> future = master.sendRequest(new ReadCoilsRequest(address, DataType.getRegisterCount(typeId)),
unitId);
ReadCoilsResponse readCoilsResponse = future.get();// 工具類做的同步返回.實(shí)際使用推薦結(jié)合業(yè)務(wù)進(jìn)行異步處理
if (readCoilsResponse != null) {
ByteBuf buf = readCoilsResponse.getCoilStatus();
result = buf.readBoolean();
ReferenceCountUtil.release(readCoilsResponse);
}
return result;
}
/**
* 讀取readDiscreteInputs開關(guān)量
*
* @param address 寄存器開始地址
* @param unitId ID
* @return 讀取值
* @throws InterruptedException 異常
* @throws ExecutionException 異常
*/
public Boolean readDiscreteInputs(int address, int unitId, int typeId)
throws InterruptedException, ExecutionException {
Boolean result = null;
CompletableFuture<ReadDiscreteInputsResponse> future = master
.sendRequest(new ReadDiscreteInputsRequest(address, DataType.getRegisterCount(typeId)), unitId);
ReadDiscreteInputsResponse discreteInputsResponse = future.get();// 工具類做的同步返回.實(shí)際使用推薦結(jié)合業(yè)務(wù)進(jìn)行異步處理
if (discreteInputsResponse != null) {
ByteBuf buf = discreteInputsResponse.getInputStatus();
result = buf.readBoolean();
ReferenceCountUtil.release(discreteInputsResponse);
}
return result;
}
/**
* 讀取HoldingRegister數(shù)據(jù)
*
* @param address 寄存器地址
* @param unitId id
* @return 讀取結(jié)果
* @throws InterruptedException 異常
* @throws ExecutionException 異常
*/
public Number readHoldingRegisters(int address, int unitId, int typeId)
throws InterruptedException, ExecutionException {
Number result = null;
CompletableFuture<ReadHoldingRegistersResponse> future = master
.sendRequest(new ReadHoldingRegistersRequest(address, DataType.getRegisterCount(typeId)), unitId);
ReadHoldingRegistersResponse readHoldingRegistersResponse = future.get();// 工具類做的同步返回.實(shí)際使用推薦結(jié)合業(yè)務(wù)進(jìn)行異步處理
if (readHoldingRegistersResponse != null) {
ByteBuf buf = readHoldingRegistersResponse.getRegisters();
result = this.getJavaType(buf, typeId);
ReferenceCountUtil.release(readHoldingRegistersResponse);
}
return result;
}
/**
* 讀取InputRegisters模擬量數(shù)據(jù)
*
* @param address 寄存器開始地址
* @param unitId ID
* @return 讀取值
* @throws InterruptedException 異常
* @throws ExecutionException 異常
*/
public Number readInputRegisters(int address, int unitId, int typeId)
throws InterruptedException, ExecutionException {
Number result = null;
CompletableFuture<ReadInputRegistersResponse> future = master
.sendRequest(new ReadInputRegistersRequest(address, DataType.getRegisterCount(typeId)), unitId);
ReadInputRegistersResponse readInputRegistersResponse = future.get();// 工具類做的同步返回.實(shí)際使用推薦結(jié)合業(yè)務(wù)進(jìn)行異步處理
if (readInputRegistersResponse != null) {
ByteBuf buf = readInputRegistersResponse.getRegisters();
result = this.getJavaType(buf, typeId);
ReferenceCountUtil.release(readInputRegistersResponse);
}
return result;
}
/**
* 轉(zhuǎn)換slave數(shù)據(jù)格式
*
* @param buf 字節(jié)容器
* @param typeId 數(shù)據(jù)庫(kù)類型id 類型id參考 com.serotonin.modbus4j.code.DataType
* @return 轉(zhuǎn)換后的數(shù)據(jù)格式
*/
private Number getJavaType(ByteBuf buf, int typeId) {
switch (typeId) {
case 2:
case 5:
case 7:
case 10:
case 12:
case 17:
case 20:
case 22:
case 25:
return buf.readInt();
case 3:
case 16:
case 23:
return buf.readShort();
case 4:
case 6:
case 11:
case 13:
case 24:
return buf.readLong();
case 14:
case 15:
return buf.readDouble();
case 8:
case 9:
case 18:
case 21:
return buf.readFloat();
default:
return null;
}
}
}
public enum ModbusEunm {
/**
* 讀線圈
*/
COILS("01"),
/**
* 讀離散輸入
*/
DISCRETE_INPUTS("02"),
/**
* 讀保存寄存器
*/
HOLDING_REGISTERS("03"),
/**
* 讀輸入寄存器
*/
INPUT_REGISTERS("04");
private String code;
ModbusEunm(String code) {
this.code = code;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
import com.syxp.dlsesp.base.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
@Entity
@Table(name = "T_MODBUS")
@ApiModel(description = "Modbus元數(shù)據(jù)")
public class ModbusEntity extends BaseEntity {
@Column(columnDefinition = "DOUBLE(9,2)")
private Double data;
@Column
@ApiModelProperty(value = "從機(jī)編號(hào)")
private Integer sId;
@Column
@ApiModelProperty(value = "功能編碼")
private String fId;
@Column
@ApiModelProperty(value = "地址編號(hào)")
private Integer address;
public Double getData() {
return data;
}
public void setData(Double data) {
this.data = data;
}
public Integer getsId() {
return sId;
}
public void setsId(Integer sId) {
this.sId = sId;
}
public String getfId() {
return fId;
}
public void setfId(String fId) {
this.fId = fId;
}
public Integer getAddress() {
return address;
}
public void setAddress(Integer address) {
this.address = address;
}
}