Java实现modbus掉电反写功能

 <dependency>
            <groupId>com.infiniteautomation</groupId>
            <artifactId>modbus4j</artifactId>
            <version>3.0.3</version>
 </dependency>
1.实现类:DeviceOperationsTask 
package com.aiswebservice.interf.quartz.task;

import com.aiswebservice.common.mapper.CommonSqlMapper;
import com.aiswebservice.common.modbusapi.ModbusTcpMaster;
import com.aiswebservice.common.scadaapi.ScadaClientApi;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.code.DataType;
import lombok.extern.slf4j.Slf4j;
import net.wimpi.modbus.Modbus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.aiswebservice.common.modbusapi.Modbus4jWriteUtils.writeHoldingRegister;

/**
 * 检测运算JOB,间隔10分钟执行一次
 */
@Slf4j
@Component
public class DeviceOperationsTask {

    @Autowired
    private CommonSqlMapper commonSqlMapper;

    @Autowired
    @Qualifier(value = "ModbusTcpMaster")
    ModbusTcpMaster masterTcp;

    public void run() throws Exception {

        try {


            String sqlTag ="select operations_id,codesys_ip,last_value, data_type,tag_addr,trueaddr,tag_des from sys_codesys_operations ORDER BY operations_id";
            List<Map<String, Object>> itemList=commonSqlMapper.ExecSelectSql(sqlTag);

            if(itemList!=null && itemList.size()>0) {
                for (Map<String, Object> mapOperations : itemList) {
                    try{
                        String data_type=mapOperations.get("data_type").toString();
                        String codesys_ip=mapOperations.get("codesys_ip").toString();
                        String trueaddr = mapOperations.get("trueaddr").toString();
                        String operations_id = mapOperations.get("operations_id").toString();
                        String tag_addr = mapOperations.get("tag_addr").toString();

                        int port = 502;

                        ModbusMaster master = masterTcp.getSlave(codesys_ip, port);

                        if(data_type.equals("DataType.FOUR_BYTE_INT_SIGNED_SWAPPED")){

                            int last_value =Integer.parseInt(mapOperations.get("last_value").toString());

                            int TagValue = Integer.parseInt(ScadaClientApi.ReadScadaTagValue(tag_addr)==null? "0":ScadaClientApi.ReadScadaTagValue(tag_addr));

                            if(last_value < TagValue && TagValue!=last_value){

                                String updateTagValueSql = "UPDATE sys_codesys_operations SET last_value ='"+TagValue+"'" +
                                        "  WHERE operations_id ='"+operations_id+"' ";

                                commonSqlMapper.ExecUpdateSql(updateTagValueSql);

                                log.info("--------------------运行时间-运算点位定时任务记录修改成功---------------------");

                            }else if(last_value >TagValue){
                                //DWordH  DataType.FOUR_BYTE_INT_SIGNED_SWAPPED 7
                                writeHoldingRegister(master, 1, Integer.parseInt(trueaddr), last_value,7);//DataType.FOUR_BYTE_INT_SIGNED_SWAPPED 7

                                log.info("--------------------运行时间-掉电反写成功---------------------");
                            }

                        }else if(data_type.equals("DataType.FOUR_BYTE_FLOAT_SWAPPED")){

                            Float last_value =Float.parseFloat(mapOperations.get("last_value").toString());

                            Float TagValue = Float.parseFloat(ScadaClientApi.ReadScadaTagValue(tag_addr)==null? "0":ScadaClientApi.ReadScadaTagValue(tag_addr));

                            if(last_value < TagValue && TagValue!=last_value){

                                String updateTagValueSql = "UPDATE sys_codesys_operations SET last_value ='"+TagValue+"'" +
                                        "  WHERE operations_id ='"+operations_id+"' ";

                                commonSqlMapper.ExecUpdateSql(updateTagValueSql);

                                log.info("--------------------累计行程-运算点位定时任务记录修改成功---------------------");

                            }else if(last_value >TagValue){

                                //float  DataType.FOUR_BYTE_FLOAT_SWAPPED  9
                                writeHoldingRegister(master, 1, Integer.parseInt(trueaddr), last_value,9);//DataType.FOUR_BYTE_FLOAT_SWAPPED  9

                                log.info("--------------------累计行程-掉电反写成功---------------------");
                            }
                        }


                    }catch (Exception e){
                        e.printStackTrace();
                    }

                }
            }

        } catch (Exception ex) {
            throw ex;

        }

    }
}

2.Modbus4jWriteUtils

package com.aiswebservice.common.modbusapi;

import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.locator.BaseLocator;
import com.serotonin.modbus4j.msg.*;

public class Modbus4jWriteUtils{

    /**
     * 写单个(线圈)开关量数据
     * 功能码为:05,开关量输出点Q置位或复位,写入数据到真机的DO类型的寄存器上面,可以读写的布尔类型(0x)
     * @param slaveId     slave的ID
     * @param writeOffset 位置-预访问的地址-地址范围:0-255
     * @param writeValue  值-置位则为1,复位则为0
     * @return 是否写入成功
     */
    public static boolean writeCoil(ModbusMaster master,int slaveId, int writeOffset, boolean writeValue){
        boolean flag = false;
        try {
            // 创建请求
            WriteCoilRequest request = new WriteCoilRequest(slaveId, writeOffset, writeValue);
            // 发送请求并获取响应对象
            WriteCoilResponse response = (WriteCoilResponse) master.send(request);
            flag =  !response.isException();
        }catch (ModbusTransportException e){
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 写多个开关量数据(线圈)
     * 功能码为:0F,写多个开关量数据(线圈)
     * @param slaveId     slaveId
     * @param startOffset 开始位置
     * @param bdata       写入的数据
     * @return 是否写入成功
     */
    public static boolean writeCoils(ModbusMaster master,int slaveId, int startOffset, boolean[] bdata) {
        boolean flag = false;
        try {
            // 创建请求
            WriteCoilsRequest request = new WriteCoilsRequest(slaveId, startOffset, bdata);
            // 发送请求并获取响应对象
            WriteCoilsResponse response = (WriteCoilsResponse) master.send(request);
            flag = !response.isException();
        }catch (ModbusTransportException e){
            e.printStackTrace();
        }
        return flag;
    }

    /***
     *  保持寄存器写单个
     *  功能码为:06,将数据写入至V存储器, 数据到真机,数据类型是Int,可以读写的数字类型(4x)
     * @param slaveId slaveId
     * @param writeOffset 开始位置
     * @param writeValue 写入的数据
     */
    public static boolean writeRegister(ModbusMaster master,int slaveId, int writeOffset, short writeValue){
        boolean flag = false;
        try {
            // 创建请求对象
            WriteRegisterRequest request = new WriteRegisterRequest(slaveId, writeOffset, writeValue);
            // 发送请求并获取响应对象
            WriteRegisterResponse response = (WriteRegisterResponse) master.send(request);
            flag = !response.isException();
        }catch (ModbusTransportException e){
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 保持寄存器写入多个模拟量数据
     * 功能码为:16,将数据写入至多个V存储器,写入数据到真机,数据类型是short[],可以读写的数字类型(4x)
     * @param slaveId     modbus的slaveID
     * @param startOffset 起始位置偏移量值
     * @param sdata       写入的数据
     * @return 返回是否写入成功
     */
    public static boolean writeRegisters(ModbusMaster master,int slaveId, int startOffset, short[] sdata) {
        boolean flag = false;
        try {
            // 创建请求对象
            WriteRegistersRequest request = new WriteRegistersRequest(slaveId, startOffset, sdata);
            // 发送请求并获取响应对象
            WriteRegistersResponse response = (WriteRegistersResponse) master.send(request);
            flag = !response.isException();
        }catch (ModbusTransportException e){
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 根据类型写数据(如:写入Float类型的模拟量、Double类型模拟量、整数类型Short、Integer、Long)
     *
     * @param value    写入值
     * @param dataType com.serotonin.modbus4j.code.DataType
     */
    public static void writeHoldingRegister(ModbusMaster master, int slaveId, int offset, Number value, int dataType) {
        try {
            // 类型
            BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, offset, dataType);
            master.setValue(locator, value);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

}

3。Modbus4jTypeUtil

package com.aiswebservice.common.modbusapi;

import com.serotonin.modbus4j.code.DataType;

public class Modbus4jTypeUtil {

    public static int getValueType(String type) {
        switch (type.toLowerCase()) {
            case "int":
                return DataType.TWO_BYTE_INT_SIGNED;
            case "long":
                return DataType.FOUR_BYTE_INT_SIGNED;
            case "long long":
                return DataType.EIGHT_BYTE_INT_SIGNED;
            case "float":
                return DataType.FOUR_BYTE_FLOAT;
            case "double":
                return DataType.EIGHT_BYTE_FLOAT;
        }
        return DataType.TWO_BYTE_INT_SIGNED;
    }

}

4.Modbus4jReadUtil 

package com.aiswebservice.common.modbusapi;

import com.serotonin.modbus4j.BatchRead;
import com.serotonin.modbus4j.BatchResults;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.code.DataType;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.locator.BaseLocator;

public class Modbus4jReadUtil {

    /**
     * 读取[01 Coil Status 0x]类型 开关数据
     *
     * @param slaveId slaveId
     * @param offset  位置
     * @return 读取值
     * @throws ModbusTransportException 异常
     * @throws ErrorResponseException   异常
     */
    public static Boolean readCoilStatus(ModbusMaster master, int slaveId, int offset, String dev_code){
        // 01 Coil Status
        BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, offset);
        try {
            return master.getValue(loc);
        }catch (Exception e){
            if (e.getMessage().equals("java.net.SocketTimeoutException: connect timed out")) System.err.println(dev_code+":"+e.getMessage());
            else e.printStackTrace();
            return null;
        }
    }


    /**
     * 读取[02 Input Status 1x]类型 开关数据
     *
     * @param slaveId
     * @param offset
     * @return
     * @throws ModbusTransportException
     * @throws ErrorResponseException
     */
    public static Boolean readInputStatus(ModbusMaster master,int slaveId, int offset,String dev_code) {
        // 02 Input Status
        BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, offset);
        try{
            return master.getValue(loc);
        }catch (Exception e){
            if (e.getMessage().equals("java.net.SocketTimeoutException: connect timed out")) System.err.println(dev_code+":"+e.getMessage());
            else e.printStackTrace();
            return null;
        }
    }


    /**
     * 读取[03 Holding Register类型 2x]模拟量数据
     *
     * @param slaveId  slave Id
     * @param offset   位置
     * @param dataType 数据类型,来自com.serotonin.modbus4j.code.DataType
     * @return
     * @throws ModbusTransportException 异常
     * @throws ErrorResponseException   异常
     */
    public static Number readHoldingRegister(ModbusMaster master,int slaveId, int offset, int dataType,String dev_code) {
        // 03 Holding Register类型数据读取
        BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType);
        try {
            return master.getValue(loc);
        }catch (Exception e){
            if (e.getMessage().equals("java.net.SocketTimeoutException: connect timed out")) System.err.println(dev_code+":"+e.getMessage());
            else e.printStackTrace();
            return null;
        }
    }


    /**
     * 读取[04 Input Registers 3x]类型 模拟量数据
     *
     * @param slaveId  slaveId
     * @param offset   位置
     * @param dataType 数据类型,来自com.serotonin.modbus4j.code.DataType
     * @return 返回结果
     * @throws ModbusTransportException 异常
     * @throws ErrorResponseException   异常
     */
    public static Number readInputRegisters(ModbusMaster master,int slaveId, int offset, int dataType,String dev_code) {
        // 04 Input Registers类型数据读取
        BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, offset, dataType);
        try{
            return master.getValue(loc);
        }catch (Exception e){
            if (e.getMessage().equals("java.net.SocketTimeoutException: connect timed out")) System.err.println(dev_code+":"+e.getMessage());
            else e.printStackTrace();
            return null;
        }
    }

    /**
     * 批量读取使用方法
     *
     * @throws ModbusTransportException
     * @throws ErrorResponseException
     */
    public static void batchRead(ModbusMaster master) throws ModbusTransportException, ErrorResponseException {
        BatchRead<Integer> batch = new BatchRead<>();
        for (int i = 0; i < 10; i++) {
            batch.addLocator(i,BaseLocator.coilStatus(1, i));
        }
        batch.setContiguousRequests(true);
        BatchResults<Integer> results = master.send(batch);
        System.out.println(results);
    }

}

5.ModbusTcpMaster

package com.aiswebservice.common.modbusapi;

import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.ip.IpParameters;
import org.springframework.stereotype.Service;

@Service(value = "ModbusTcpMaster")
public class ModbusTcpMaster {
    private final ModbusFactory modbusFactory = new ModbusFactory();

    /**
     * 获取slave
     * @return
     * @throws ModbusInitException
     */
    public ModbusMaster getSlave(String ip, int port) {
        ModbusMaster master = null;
        try {
            IpParameters params = new IpParameters();
            params.setHost(ip);
            params.setPort(port);
            //这个属性确定了协议帧是否是通过tcp封装的RTU结构,采用modbus tcp/ip时,要设为false, 采用modbus rtu over tcp/ip时,要设为true
            params.setEncapsulated(false);
            // modbusFactory.createRtuMaster(wapper); //RTU 协议
            // modbusFactory.createUdpMaster(params);//UDP 协议
            // modbusFactory.createAsciiMaster(wrapper);//ASCII 协议
            master = modbusFactory.createTcpMaster(params, false);
            //最大等待时间
            master.setTimeout(2000);
            //最大连接次数
            master.setRetries(5);
            master.init();
        } catch (ModbusInitException e) {
            e.printStackTrace();

        }
        return master;
    }
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值