IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> java解析SZY206-2016传输规约 -> 正文阅读

[Java知识库]java解析SZY206-2016传输规约

帧结构(报文结构)

请添加图片描述


示例:681A68B35303810D00C00059000000826110000001106000004508090A3516

  1. 681A68:开始字符串 字符串长度 开始字符串

  2. B3为控制域(数据类型)

    1)0000B—雨量;

  1. 0001B—水位;
  2. 0010B—流量(水量);
  3. 0011B—流速;
  4. 0100B—闸位;
  5. 0101B—功率;
  6. 0110B—气压;
  7. 0111B—风速(风向);
  8. 1000B—水温;
  9. 1001B—水质;
  10. 1010B—土壤含水率;
  11. 1011B—水压;
  12. 1100B—1111B 备用。
  1. 5303810D00为地址域(测站地址) 22 24 06为行政区代码 07 00测站地址
  2. 0059000000826110000001106000004508090A 用户数据(报文正文)
  3. 35: 校验CS
  4. 16: 结束字符(固定)


用户数据域解析(正文解析)

正文需要从后面开始解析

正文:0059000000826110000001106000004508090A

  1. 后10位为时间 :004508090A //00(秒-十位个位)45(分-十位个位)08(时-十位个位)09(日-十位个位),解析后为09日 08:45:00 年月需要自己补充。

  2. 再往前8位 01106000为报警值 转换为2进制 00000001000100000000011000000000 (每位转成4位2进制数不足补0)

    前16位数
    请添加图片描述

    后16位数

    请添加图片描述


  3. 剩余的为相关数据 00590000008261100000

    由于数据类型为 B3 0010B—流量(水量)

    按照文档6.2.26解析各种类型的数据

请添加图片描述



传输规约是5个字节代表一个数据,00 59 00 00 00 为流量数据,82 61 10 00 00 为水量数据

再按照每个位置代表的 数字位数解析后

流量为 00 00 00 59 00 实际数据为5.9 m3/s
水量 00 00 10 61 82 实际为106182 m3/h

请添加图片描述

java代码

package com.southsmart.smartwater.lotdevice.parser;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.southsmart.smartwater.lotdevice.constant.DataInfoConstant;
import com.southsmart.smartwater.lotdevice.enums.Szy206TypeEnum;
import com.southsmart.smartwater.lotdevice.enums.Szy206WaterQualityEnum;
import com.southsmart.smartwater.lotdevice.mapper.LotDeviceMapper;
import com.southsmart.smartwater.lotdevice.model.dto.Szy206InfoDTO;
import com.southsmart.smartwater.lotdevice.model.dto.UrlDTO;
import com.southsmart.smartwater.lotdevice.model.po.LotDevicePO;
import com.southsmart.smartwater.lotdevice.parser.service.ParserService;
import com.southsmart.smartwater.lotdevice.utils.MathUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * @author c
 * @version 1.0
 * @description TODO
 * @since 2022/6/20
 */
@Slf4j
@Service
public class Szy206Parser extends BaseParser {
    @Autowired
    private LotDeviceMapper lotDeviceMapper;
    @Autowired
    private ParserService parserService;
    @Override
    public UrlDTO getUrlInfo(String interfaceId, String deviceId) {
        return null;
    }

    @Override
    public Map<String, Object> dataParser(String msg, String deviceId) {
        Szy206InfoDTO szy206InfoDTO=new Szy206InfoDTO();
        //示例 681A68B35303810D00C00059000000826110000001106000004508090A3516

        //681A68开始字符串 字符串长度 开始字符串
        Integer index=0;
        //开始字符串
        String startStr=msg.substring(index,index+6);
        szy206InfoDTO.setStartStr(startStr);
        index+=6;


        //B3为数据类型(流量(水量))
        //1) 0000B—雨量;
        //2) 0001B—水位;
        //3) 0010B—流量(水量);
        //4) 0011B—流速;
        //5) 0100B—闸位;
        //6) 0101B—功率;
        //7) 0110B—气压;
        //8) 0111B—风速(风向);
        //9) 1000B—水温;
        //10) 1001B—水质;
        //11) 1010B—土壤含水率;
        //12) 1011B—水压;
        //13) 1100B—1111B 备用。

        //数据类型
        String dataType=msg.substring(index,index+2);
        szy206InfoDTO.setDataType(dataType);
        index+=2;

        //5303810D00为测站地址  530381为行政区代码  0D00测站地址
        //遥测地址
        String stationAddr=msg.substring(index,index+10);
        szy206InfoDTO.setStationAddr(stationAddr);
        szy206InfoDTO.setDeviceId(stationAddr);
        index+=10;
        //C0   C0H遥测终端自报实时数据 遥测终端 中心站
        //应用层功能码
        String functionCode=msg.substring(index,index+2);
        szy206InfoDTO.setFunctionCode(functionCode);
        index+=2;
        //0059000000826110000001106000004508090A  报文正文
        //正文
        String content=msg.substring(index,msg.length()-4);
        szy206InfoDTO.setContent(content);
        index=msg.length()-4;
        //35 crc校验
        //crc校验码
        String crcCode=msg.substring(index,index+2);
        szy206InfoDTO.setCrcCode(crcCode);
        index+=2;
        //16 结束字符(固定)
        //结束字符串16
        String endStr=msg.substring(index,index+2);
        szy206InfoDTO.setEndStr(endStr);

        parseContent(content,szy206InfoDTO);
        Map<String,Object> map= (Map<String, Object>) JSONUtil.parse(szy206InfoDTO);
        return map;

    }

    private void parseContent(String content, Szy206InfoDTO szy206InfoDTO) {
        Map<String,Object> mainBody=new HashMap<>();
        Map<String,Object> mainHead=new HashMap<>();
        //倒着解析
        int index=content.length();
        if(index>18){
            //004508090A
            //00(秒-十位个位)45(分-十位个位)08(时-十位个位)09(日-十位个位),解析后为09日 08:45:00 年月需要自己补充。
            String time=content.substring(index-10,index);
            Integer year= DateTime.now().year();
            Integer month=DateTime.now().monthBaseOne();
            Integer day=Integer.parseInt(time.substring(6,8));
            Integer hour=Integer.parseInt(time.substring(4,6));
            Integer minutes=Integer.parseInt(time.substring(2,4));
            Integer seconds=Integer.parseInt(time.substring(0,2));
            String dateTimeStr=year+"/"+month+"/"+day+" "+hour+":"+minutes+":"+seconds;
            DateTime dateTime= DateUtil.parseDateTime(dateTimeStr);
            String timeStr= dateTime.toString();
            szy206InfoDTO.setDataTime(timeStr);

            mainBody.put(DataInfoConstant.DATA_TIME,timeStr);
            mainHead.put(DataInfoConstant.DATA_TIME,DataInfoConstant.DATA_TIME_MEAN);
            index-=10;
            String warningStatus=content.substring(index-8,index);
            index-=8;
            String dataContent=content.substring(0,index);
            if(Szy206TypeEnum.WATER_LEVEL.getKey().equals(szy206InfoDTO.getDataType())){
                //水位

                //每N个数组 代表一个数据
                int oneDataLength=8;
                //小数点位数
                int decimalPoint=5;

                parentDataInfo(szy206InfoDTO,dataContent,oneDataLength,decimalPoint,true,mainBody,mainHead);
            }else if(Szy206TypeEnum.TRAFFIC.getKey().equals(szy206InfoDTO.getDataType())){
                //流量

                //每N个数组 代表一个数据
                int oneDataLength=10;
                //小数点位数
                int decimalPoint=7;
                int dataLength=dataContent.length();
                if(dataLength%oneDataLength==0) {
                    int cycleNum = 0;
                    int flag=2;
                    while (dataLength > 0) {
                        try {
                            String data = dataContent.substring(cycleNum * oneDataLength, (cycleNum + 1) * oneDataLength);
                            cycleNum++;
                            dataLength -= oneDataLength;
                            char[] dataChar = data.toCharArray();
                            String result;
                            //实时流量在前 累计流量在后
                            if(flag%2==0){
                                //流量实时数据
                                result = char2String(dataChar, decimalPoint,true);
                                Double resultData=Double.parseDouble(result);
                                mainBody.put("flow",resultData);
                                mainHead.put("flow","流量");
                                log.info("遥测地址:"+szy206InfoDTO.getStationAddr()+" 类型:流量"+" 结果:"+resultData);
                            }else{
                                //累计流量(水量)
                                result = char2String(dataChar, 0,true);
                                Double resultData=Double.parseDouble(result);
                                mainBody.put("countFlow",resultData);
                                mainHead.put("countFlow","累计流量");
                                log.info("遥测地址:"+szy206InfoDTO.getStationAddr()+" 类型:累计流量"+" 结果:"+resultData);
                            }
                            flag++;


                        } catch (Exception e) {
                            System.out.println(e.toString());
                        }
                    }
                }
            }else if(Szy206TypeEnum.VELOCITY.getKey().equals(szy206InfoDTO.getDataType())){
                //流速

                //每N个数组 代表一个数据
                int oneDataLength=6;
                //小数点位数
                int decimalPoint=3;
                parentDataInfo(szy206InfoDTO,dataContent,oneDataLength,decimalPoint,true,mainBody,mainHead);
            }else if(Szy206TypeEnum.GATES.getKey().equals(szy206InfoDTO.getDataType())){
                //每N个数组 代表一个数据
                int oneDataLength=6;
                //小数点位数
                int decimalPoint=4;
                parentDataInfo(szy206InfoDTO,dataContent,oneDataLength,decimalPoint,false,mainBody,mainHead);
            }else if(Szy206TypeEnum.POWER.getKey().equals(szy206InfoDTO.getDataType())){
                //每N个数组 代表一个数据
                int oneDataLength=6;
                //小数点位数
                int decimalPoint=0;
                parentDataInfo(szy206InfoDTO,dataContent,oneDataLength,decimalPoint,false,mainBody,mainHead);
            }else if(Szy206TypeEnum.AIR_PRESSURE.getKey().equals(szy206InfoDTO.getDataType())){
                //每N个数组 代表一个数据
                int oneDataLength=6;
                //小数点位数
                int decimalPoint=0;
                parentDataInfo(szy206InfoDTO,dataContent,oneDataLength,decimalPoint,false,mainBody,mainHead);
            }else if(Szy206TypeEnum.WIND_SPEED.getKey().equals(szy206InfoDTO.getDataType())){
                //每N个数组 代表一个数据
                int oneDataLength=6;
                //小数点位数
                int decimalPoint=4;
                parentDataInfo(szy206InfoDTO,dataContent,oneDataLength,decimalPoint,false,mainBody,mainHead);
            }else if(Szy206TypeEnum.WATER_TEMPERATURE.getKey().equals(szy206InfoDTO.getDataType())){
                //每N个数组 代表一个数据
                int oneDataLength=4;
                //小数点位数
                int decimalPoint=3;
                parentDataInfo(szy206InfoDTO,dataContent,oneDataLength,decimalPoint,false,mainBody,mainHead);
            }else if(Szy206TypeEnum.MOISTURE_CONTENT.getKey().equals(szy206InfoDTO.getDataType())){
                //每N个数组 代表一个数据
                int oneDataLength=4;
                //小数点位数
                int decimalPoint=4;
                parentDataInfo(szy206InfoDTO,dataContent,oneDataLength,decimalPoint,false,mainBody,mainHead);
            }else if(Szy206TypeEnum.WATER_PRESSURE.getKey().equals(szy206InfoDTO.getDataType())){
                //每N个数组 代表一个数据
                int oneDataLength=8;
                //小数点位数
                int decimalPoint=7;
                parentDataInfo(szy206InfoDTO,dataContent,oneDataLength,decimalPoint,false,mainBody,mainHead);
            }else if(Szy206TypeEnum.WATER_QUALITY.getKey().equals(szy206InfoDTO.getDataType())){
                //水质
                //每N个数组 代表一个数据
                int oneDataLength=8;
                //前十位是检测种类
                String typeStr=dataContent.substring(0,10);
                //每位转成4位二进制数 前面补0
                char[] typeChar=typeStr.toCharArray();
                String binStr="";
                for(char ch:typeChar){
                    binStr+=MathUtil.hexString2binaryString(new StringBuilder(ch).toString());
                }
                //更加2进制字符串判断 存在哪些水质参数 1代表存在。
                char[] binaryTypeChar=binStr.toCharArray();
                //存在粪大肠菌群的话 每5个字符代表一个数值 否则4个   (5+N*4(+1【参数含粪大肠菌群时】)+4 个字节。)
                if(new StringBuilder(binaryTypeChar[24]).toString().equals("1")){
                    oneDataLength=10;
                }
                List<Integer> indexList=new ArrayList<>();
                //记录1的位置
                for(int i=0;i<binaryTypeChar.length;i++){
                    if(new StringBuilder(binaryTypeChar[i]).toString().equals("1")){
                        indexList.add(i);
                    }
                }

                //获取所有数据list
                int dataLength=dataContent.length();
                List<String> dataList=new ArrayList<>();
                if(dataLength%oneDataLength==0) {
                    int cycleNum=0;
                    while (dataLength > 0) {
                        String data = dataContent.substring(cycleNum * oneDataLength, (cycleNum + 1) * oneDataLength);
                        dataList.add(data);
                    }
                }

                if(indexList.size()==dataList.size()){
                   for(int i=0;i<indexList.size();i++){
                       Szy206WaterQualityEnum szy206WaterQualityEnum =getQualityEnumByKey("D"+indexList.get(i));
                       if(ObjectUtil.isNotEmpty(szy206WaterQualityEnum)){
                           //N(3,1) oneDataLength-3+(3-1)  ==oneDataLength-1; 00000123 小数位数为7
                           Integer decimalPoint=oneDataLength-Integer.parseInt(szy206WaterQualityEnum.getPrecision().split(",")[1].replace(")",""));
                           //TODO不确定是直接将数字倒序就行还是 以下方式(待验证)
                           Double value=Double.parseDouble(char2String(dataList.get(i).toCharArray(),decimalPoint,false));
                           String key=szy206WaterQualityEnum.getKey();
                           log.info("遥测地址:"+szy206InfoDTO.getStationAddr()+"类型:"+szy206WaterQualityEnum.getName()+"结果:"+value);
                           mainBody.put(key,value);
                           mainHead.put(key,szy206WaterQualityEnum.getName()+"("+szy206WaterQualityEnum.getUnit()+")");
                       }
                   }
                }
            }

        }
        szy206InfoDTO.setMainBody(mainBody);
        szy206InfoDTO.setMainHead(mainHead);
    }

    public Szy206WaterQualityEnum getQualityEnumByKey(String key){
        for(Szy206WaterQualityEnum e:Szy206WaterQualityEnum.values()){
            if(e.getKey().equals(key)){
                return e;
            }
        }
        return null;
    }

    /**
     * 解析正文
     * @param szy206InfoDTO 解析实体
     * @param dataContent 正文
     * @param oneDataLength 一个数据长度
     * @param decimalPoint 小数位数
     * @param isNegative 是否判断正方
     * @param mainBody 数据
     * @param mainHead 头部
     */
    public void parentDataInfo( Szy206InfoDTO szy206InfoDTO,String dataContent,Integer oneDataLength, int decimalPoint,Boolean isNegative,Map<String,Object> mainBody,Map<String,Object> mainHead){

        int dataLength=dataContent.length();
        if(dataLength%oneDataLength==0){
            int cycleNum=0;
            while (dataLength>0){
                try{
                    String data=dataContent.substring(cycleNum*oneDataLength,(cycleNum+1)*oneDataLength);
                    cycleNum++;
                    dataLength-=oneDataLength;
                    char[] dataChar=data.toCharArray();
                    String result=char2String(dataChar,decimalPoint,isNegative);
                    Szy206TypeEnum szy206TypeEnum=getTypeEnum(szy206InfoDTO.getDataType());
                    //数据值
                    Double resultData=Double.parseDouble(result);
                    mainBody.put(szy206TypeEnum.getKey(),resultData);
                    mainHead.put(szy206TypeEnum.getKey(),szy206TypeEnum.getDescription());

                    log.info("遥测地址:"+szy206InfoDTO.getStationAddr()+" 类型:"+szy206TypeEnum.getDescription()+" 结果:"+result);
                }catch (Exception e){
                    System.out.println(e.toString());
                }
            }

        }
    }

    public Szy206TypeEnum getTypeEnum(String typeKey){
        for(Szy206TypeEnum szy206TypeEnum:Szy206TypeEnum.values()){
            if(szy206TypeEnum.getKey().equals(typeKey)){
                return szy206TypeEnum;
            }
        }
        return null;
    }


    public String char2String(char[] ch,Integer decimalPoint,Boolean isNegative){
        //将char 2位分为一组 并倒序排列
        int length=ch.length/2;
        String[] dataArray=new String[length];
        for(int i=0;i<ch.length;i+=2){
            String c=ch[i]+""+ch[i+1];
            dataArray[length-1]=c;
            length--;
        }


        StringBuilder stringBuilder=new StringBuilder();

        for(int j=0;j<dataArray.length;j++){
            if(j==0){
                if(isNegative){
                    //第一位代表+ -值
                    if(Integer.parseInt(dataArray[j].substring(0,1))!=0){
                        stringBuilder.append("-");
                    }else{
                        stringBuilder.append("+");
                    }
                    stringBuilder.append(dataArray[j].substring(1,2));
                }
            }else{
                stringBuilder.append(dataArray[j]);
            }
        }
        String resultDataStr=stringBuilder.toString();
        //添加小数点
        if(decimalPoint!=0){
            resultDataStr=stringBuilder.toString().substring(0,decimalPoint)+"."+stringBuilder.toString().substring(decimalPoint,stringBuilder.length());
        }

        return resultDataStr;
    }
}

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-06-26 16:47:16  更:2022-06-26 16:49:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 16:30:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码