工业消防信息接入Java

1、消防主机设置

2、接口文档

详细

3、编写程序

server端加上特殊字符解码器

b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            //分隔符
                            ByteBuf delimiter = Unpooled.copiedBuffer("##".getBytes());
                            //特殊字符结束符包解析
                            ch.pipeline().addLast(new DelimiterBasedFrameDecoder(ParamManage.MAXLENGTH,
                                    false,
                                    true,
                                    delimiter));

                            ch.pipeline().addLast(new ServerHandler());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

处理handler

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        byte[] req = new byte[buf.readableBytes()];
        buf.readBytes(req);

        String strReq = Util.bytesToHexString(req);
        log.info("收到的请求是:" + strReq);

        if(StrUtil.isNotEmpty(strReq)){
            log.info(AnalysisUtil.getSendTime(req));
            log.info(AnalysisUtil.getSourceAddress(req));
            log.info(AnalysisUtil.getDestinationAddress(req));
            int unitLength = (req[24] & 0xff) + ((req[25] & 0xff) << 8);
            log.info("unitLength = " + unitLength);

            int command = req[26] & 0xff;
            log.info("command = " + command);


            int messageLength = 30;
            if (unitLength > 0 && req.length == messageLength + unitLength){
                servicesHandle(req);
            }

            if (req.length != messageLength + unitLength){
                byte[] result = new ResponseBean().fail(req);
                log.info("MESSAGE LENGTH ERROR,FAIL MESSAGE:" + Util.bytesToHexString(result));
                ByteBuf echo = Unpooled.copiedBuffer(result);
                ctx.writeAndFlush(echo);
            }else{
                byte[] result = new ResponseBean().success(req);
                log.info("RIGHT,RESPOND:" + Util.bytesToHexString(result));
                ByteBuf echo = Unpooled.copiedBuffer(result);
                ctx.writeAndFlush(echo);
            }


        }else{
            ByteBuf echo= Unpooled.copiedBuffer(new ResponseBean().wrongFormat());
            ctx.writeAndFlush(echo);
        }




        super.channelRead(ctx, msg);
    }

统一返回bean

public class ResponseBean {

    private static final String SUCCESS = "SUCCESS";
    private static final String FAIL = "FAIL";

    public byte[] success(byte[] bytes){
        return handle(bytes,SUCCESS);
    }

    public byte[] wrongFormat(){
        return handle(null,null);
    }

    public byte[] fail(byte[] bytes){
        return handle(bytes,FAIL);
    }

    private byte[] handle(byte[] bytes ,String command){
        Calendar c = Calendar.getInstance();
        int second = c.get(Calendar.SECOND) & 0xff;
        int minute = c.get(Calendar.MINUTE) & 0xff;
        int hour = c.get(Calendar.HOUR_OF_DAY) & 0xff;
        int day = c.get(Calendar.DATE) & 0xff;
        int month = (c.get(Calendar.MONTH) + 1) & 0xff;
        int year = Integer.parseInt(String.valueOf(c.get(Calendar.YEAR)).substring(2)) & 0xff;


        if(SUCCESS.equals(command) || FAIL.equals(command)){
            byte[] comBytes = new byte[] { bytes[2],  bytes[3], (byte)0x01, (byte)0x01,
                    (byte)second, (byte)minute, (byte)hour,(byte)day,(byte)month,(byte)year,
                    bytes[18], bytes[19], bytes[20],bytes[21],bytes[22],bytes[23],
                    bytes[12], bytes[13], bytes[14],bytes[15],bytes[16],bytes[17],(byte)0x00, (byte)0x00, SUCCESS.equals(command) ? (byte)0x03 : (byte)0x06};

            byte crc = calCRC(comBytes);

            byte[] result = new byte[]{(byte)0x40, (byte)0x40,
                    bytes[2],  bytes[3], (byte)0x01, (byte)0x01,
                    (byte)second, (byte)minute, (byte)hour,(byte)day,(byte)month,(byte)year,
                    bytes[18], bytes[19], bytes[20],bytes[21],bytes[22],bytes[23],
                    bytes[12], bytes[13], bytes[14],bytes[15],bytes[16],bytes[17],(byte)0x00, (byte)0x00, SUCCESS.equals(command) ? (byte)0x03 : (byte)0x06,
                    crc,(byte)0x23, (byte)0x23};
            return result;
        }else{
            byte[] comBytes = new byte[] { (byte)0x00,  (byte)0x00, (byte)0x01, (byte)0x01,
                    (byte)second, (byte)minute, (byte)hour,(byte)day,(byte)month,(byte)year,
                    (byte)0x00, (byte)0x00, (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
                    (byte)0x00, (byte)0x00, (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00, (byte)0x00,(byte)0x06};
            byte crc = calCRC(comBytes);
            byte[] result = new byte[]{(byte)0x40, (byte)0x40,
                    (byte)0x00,  (byte)0x00, (byte)0x01, (byte)0x01,
                    (byte)second, (byte)minute, (byte)hour,(byte)day,(byte)month,(byte)year,
                    (byte)0x00, (byte)0x00, (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
                    (byte)0x00, (byte)0x00, (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00, (byte)0x00,(byte)0x06,
                    crc,(byte)0x23, (byte)0x23};

            return result;
        }

    }



    private byte calCRC(byte[] data){
        int sum = 0, len = data.length;

        for (int i = 0; i < len; i++){
            sum += data[i];
        }
        byte crc = (byte)(sum & 0xff);
        return crc;
    }
}

应用数据单元类型标志定义表
类型值说明方向
0 预留上行
1 上传建筑消防设施系统状态
2 上传建筑消防设施部件运行状态
3 上传建筑消防设施部件模拟量值
4 上传建筑消防设施操作信息
5 上传建筑消防设施软件版本
6 上传建筑消防设施系统配置情况
7 上传建筑消防设施部件配置情况
8 上传建筑消防设施系统时间
9~20 预留(建筑消防设施信息) 
21 上传用户信息传输装置运行状态
22 预留
23 预留
24 上传用户信息传输装置操作信息
25 上传用户信息传输装置软件版本
26 上传用户信息传输装置配置情况
27 预留
28 上传用户信息传输装置系统时间
29~40 预留(用户信息传输装置信息) 
41~60 预留(控制信息) 
61 读建筑消防设施系统状态下行
62 读建筑消防设施部件运行状态
63 读建筑消防设施部件模拟量值
64 读建筑消防设施操作信息
65 读建筑消防设施软件版本
66 读建筑消防设施系统配置情况
67 读建筑消防设施部件配置情况
68 读建筑消防设施系统时间
69~80 顶留
81 读用户信息传输装置运行状态
82 预留
83 预留
84 读用户信息传输装置操作信息记录
85 读用户信息传输装置软件版本
86 读用户信息传输装置配置情况
87 预留
88 读用户信息传输装置系统时间
89 初始化用户信息传输装置
90 同步用户信息传输装置时钟
91 查岗命令
92~127 预留
128~254 用户自定义
128上传用户信息传输装置生产日期上行
129上传用户报名信息
130上传用户信息传输装置开机时间信息
131上传用户信息传输装置关机时间信息
132上传建筑消防设施系统开机信息
133上传建筑消防设施系统关机信息
134上传建筑消防设施系统状态恢复
135上传建筑消防设施部件运行状态恢复
136上传用户信息传输装置运行状态恢复
137上传建筑消防设施部件运行状态(自定义)
138上传建筑消防设施部件运行状态(自定义)恢复
139上传用户信息传输装置用户身份识别信息
140上传建筑消防设施系统状态(自定义)
141上传建筑消防设施系统状态(自定义)恢复
188读用户信息传输装置生产日期下行
189设置用户信息传输装置报名时间
197读建筑消防设施部件运行状态(自定义)

demo目前处理2种类型

case 2    处理方法

public static void faultAlarm(byte[] bytes, int nums){
        for (int i = 0; i < nums; i++) {
            //系统类型
            int sysType = bytes[29 + i * 46] & 0xff;
            //系统地址
            int sysAddress = bytes[30 + i * 46] & 0xff;
            //部件地址
            int parts = bytes[31 + i * 46] & 0xff;


            log.info("sysType:"+sysType+" sysAddress:"+sysAddress+" parts:"+parts);




            int mill = (bytes[69+ i * 46] & 0xff);
            int minute = (bytes[70+ i * 46] & 0xff);
            int hour = (bytes[71+ i * 46] & 0xff);
            int day = (bytes[72+ i * 46] & 0xff);
            int month = (bytes[73+ i * 46] & 0xff);
            int year = (bytes[74+ i * 46] & 0xff);
            Date createTime = null;

            try {
                createTime = new SimpleDateFormat( "yy-MM-dd HH:mm:ss" ).parse(year+"-"+month+"-"+day+ " " +
                        hour + ":"+ minute + ":" + mill);
            } catch (ParseException e) {
                e.printStackTrace();
            }


            // 上传部件地址与消防系统设备地址的对应关系
            String deviceAddress = AddressMapping.getDeviceAddress(bytes[32 + i * 46], bytes[33 + i * 46], bytes[34 + i * 46], bytes[35 + i * 46]);


            //火警
            int data1 = bytes[36+ i * 46] >>> 1 & 0x1;
            //故障
            int data2 = bytes[36+ i * 46] >>> 2 & 0x1;

            if(data1 == 1){
                log.warn("火警"+deviceAddress+" "+createTime);
            }
            if(data2 == 1){
                log.warn("故障"+deviceAddress+" "+createTime);
            }


        }



    }

地址对应关系可以查看文档

附上地址对应处理方法。部分type 试过 ,常用为0,1,2,3

public static String getDeviceAddress(byte lowBit, byte highBit, byte lowArea, byte highArea){

        int bitCode;
        bitCode = (lowBit & 0xff);
        bitCode += (highBit & 0xff) << 8;
        int areaCode;
        areaCode = (lowArea & 0xff);
        areaCode += (highArea & 0xff) << 8;


        log.info("bitCode:"+bitCode+" areaCode:"+areaCode);
        String tempAreaCode = String.format("%05d", areaCode);
        String arrCode="";

        switch (TYPE){
            case 0 :
                //回路号 -设备号
                arrCode = areaCode + "-" + bitCode;
                break;
            case 1 :
                //主机号2 -回路号3 -设备号
                arrCode = Integer.parseInt(tempAreaCode.substring(0,2)) + "-" + Integer.parseInt(tempAreaCode.substring(2)) + "-" + String.format("%03d", bitCode);
                break;
            case 2 :
                //主机号3 -回路号2 -设备号
                arrCode = Integer.parseInt(tempAreaCode.substring(0,3)) + "-" + Integer.parseInt(tempAreaCode.substring(3)) + "-" + String.format("%03d", bitCode);
                break;
            case 3 :
                arrCode += highArea & 0xff;
                arrCode += lowArea & 0xff;
                arrCode += highBit & 0xff;
                arrCode += lowBit & 0xff;
                break;
            case 4 :
                //栋/区/层/设备号
                arrCode += ((highArea & 0xff) +"/");
                arrCode += ((lowArea & 0xff) +"/");
                arrCode += ((highBit & 0xff) +"/");
                arrCode += ((lowBit & 0xff) +"/");
                break;
            default:
                break;
        }

        return arrCode;
    }

4、测试报文

------无数据包
4040 @@
0000 流水号
01	主版本号
01	协议版本号
07 7秒
1D 29分
0A 10时
1B 27日
04 4月
16 22年
F60100000000	源地址
FE7900000000	目标地址
0000 应用数据长度
02	命令
D5	校验和
2323 ##



------手报


4040
0100
01
01
30 30s
2A 42
0D 13h
07
05
16
F60100000000
FE7900000000
0A 00 10L
02					
1801040A002A0D070516 数据长度    18 为24是系统类型标志( 上传用户信息传输装置操作信息)  002A0D070516 时间
86
2323


------火警

4040
0500
01
01
16
2A
0E
11
05
16
410100000000
2A3000000000
3000 48L
02
02010101007100E903020020202020202020202020202020202020202020202020202020202020202000002A0E110516
D7
2323






02
01
01 系统类型
01 系统地址
00 部件类型
7100 位号(设备号) 113   01110001  00000000
E903 区号(      )1001   11101001  00000011
0200 数据
20202020202020202020202020202020202020202020202020202020202000 部件说明
002A0E110516 时间

祝各位成功

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值