SpringBoot 2.2.6 集成ModbusTCP協(xié)議 請(qǐng)求從站獲取數(shù)據(jù)

概要

  1. 轉(zhuǎn)載地址
  2. 通過(guò)后端集成ModbusTCP協(xié)議,主動(dòng)請(qǐng)求從站獲取數(shù)據(jù)。
  3. 因甲方方案調(diào)整,此代碼最終未采用,故也未進(jìn)行更多的處理與優(yōu)化。

什么是Modbus TCP

image.png

如何集成Modbus TCP MASTER

  1. 仿真機(jī)下載地址 仿真機(jī)有主站和從站 需要模擬從站 下載 Modbus Slave 激活碼 5455415451475662

  2. 添加依賴(lài)

implementation 'com.digitalpetri.modbus:modbus-master-tcp:1.1.0'
  1. 貼代碼
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開(kāi)關(guān)量
     *
     * @param address 寄存器開(kāi)始地址
     * @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();// 工具類(lèi)做的同步返回.實(shí)際使用推薦結(jié)合業(yè)務(wù)進(jìn)行異步處理
        if (readCoilsResponse != null) {
            ByteBuf buf = readCoilsResponse.getCoilStatus();
            result = buf.readBoolean();
            ReferenceCountUtil.release(readCoilsResponse);
        }
        return result;
    }

    /**
     * 讀取readDiscreteInputs開(kāi)關(guān)量
     *
     * @param address 寄存器開(kāi)始地址
     * @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();// 工具類(lèi)做的同步返回.實(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();// 工具類(lèi)做的同步返回.實(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 寄存器開(kāi)始地址
     * @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();// 工具類(lèi)做的同步返回.實(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ù)類(lèi)型id 類(lèi)型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;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容