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. 添加依賴

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開關(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;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末坠韩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子炼列,更是在濱河造成了極大的恐慌只搁,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件唯鸭,死亡現(xiàn)場(chǎng)離奇詭異须蜗,居然都是意外死亡硅确,警方通過(guò)查閱死者的電腦和手機(jī)目溉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)菱农,“玉大人缭付,你說(shuō)我怎么就攤上這事⊙矗” “怎么了陷猫?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)的妖。 經(jīng)常有香客問(wèn)我绣檬,道長(zhǎng),這世上最難降的妖魔是什么嫂粟? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任娇未,我火速辦了婚禮,結(jié)果婚禮上星虹,老公的妹妹穿的比我還像新娘零抬。我一直安慰自己镊讼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布平夜。 她就那樣靜靜地躺著蝶棋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪忽妒。 梳的紋絲不亂的頭發(fā)上玩裙,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音段直,去河邊找鬼献酗。 笑死,一個(gè)胖子當(dāng)著我的面吹牛坷牛,可吹牛的內(nèi)容都是我干的罕偎。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼京闰,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼颜及!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起蹂楣,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤俏站,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后痊土,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肄扎,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年赁酝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了犯祠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡酌呆,死狀恐怖衡载,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情隙袁,我是刑警寧澤痰娱,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站菩收,受9級(jí)特大地震影響梨睁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜娜饵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一坡贺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦拴念、人聲如沸钧萍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)风瘦。三九已至,卻和暖如春公般,著一層夾襖步出監(jiān)牢的瞬間万搔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工官帘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瞬雹,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓刽虹,卻偏偏與公主長(zhǎng)得像酗捌,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子涌哲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349