欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 维修 > 645协议解析-js脚本

645协议解析-js脚本

2025/2/25 16:56:42 来源:https://blog.csdn.net/LM0916/article/details/144987966  浏览:    关键词:645协议解析-js脚本

         最近项目中用js写了一个关于645协议的解析脚本。其中解析了部分字段,大部分是用于抄读的功能,支持时间和日期的读写。在这里记录。如果是前端的同志,可以忽略,因为这个属于公司项目中的偏业务层面的脚本,感觉跟前端关系不大,只是语言使用了js而已,不过花了挺多时间的,所以想在这里记录留念一下。以后再做这方面的协议解析报文的工作会有经验一点。

 解析示例

// 以下为脚本模版,您可以基于以下模版进行脚本编写/*** 物模型方法*/
const METHOD = {post: 'thing.event.property.post',get: 'thing.service.property.get',set: 'thing.service.property.set',action: 'thing.service.{identifier}',
}/*** 设备到云消息解析* 将设备的自定义格式数据转换为标准协议的数据,设备上报数据到物联网平台时调用* 模拟执行输入参数示例 {"data":"FE0304229401197EF2","identifier":"Version"}* @param {string} jsonString "{\"data\": \"FE0304229401197EF2\", \"identifier\": \"Version\"}"* @param {string} jsonString.data 报文帧* @param {string} jsonString.identifier 物模型标识符* @returns {object} result* @returns {string} result.data 物模型属性值* @returns {string} result.identifier 物模型标识符* @returns {string} result.method 物模型方法 * thing.event.property.post (主动上报) | thing.service.property.get (属性获取) | thing.service.property.set (属性设置) | thing.service.${identifier} (动作调用)*/
function rawDataToProtocol(jsonString) {const jsonObj = {}return jsonObj
}/*** 云到设备消息解析* 将标准协议的数据转换为设备能识别的格式数据,物联网平台给设备下发数据时调用* 模拟执行输入参数,示例 {"address":"1","functionCode":"0x04","params":{"FlowRate":true}, "deviceName": "123456789012"}* @param {string} jsonString "{\"address\":\"1\",\"functionCode\":\"0x04\",\"params\":{\"FlowRate\":true}, \"deviceName\":\"123456789012\"}"* @param {string} jsonString.address 从机地址* @param {string} jsonString.functionCode 功能码* @param {object} jsonString.params 标识符 key-value 对* @param {string} jsonString.deviceName 设备名称* @returns {string} rawdata 设备能识别的格式数据*/
function protocolToRawData(jsonObj) {const rawdata = ''return rawdata
}

 645协议部分数据标识解析-js脚本

/*** 前提:此脚本目前仅支持读取数据并且仅支持FUNCTION_CODE_MAP中的数据标识读取,并且仅支持一次读取一个数据标识的情况*		仅支持时间和日期的写入** 属性的控制码C:读数据 11H(设备接收-读数据)| 91H(设备上报-无后续数据帧)| D1H 异常应答帧*				  写数据 14H(设备接收-写数据)| 94H(设备上报-无后续数据帧)| D4H 异常应答帧* funCode:数据标识;顺序是:DI3 DI2 DI1 DI0* long:设备上报的数据长度(单位:字节),这里long是16进制, 2 => 0x02* dataFormat:数据格式,保留几位小数* desc:属性内容* symbol:0正1负号  (有些数据上报的值需要考虑正负)* ASCII  :是否按照ASCII解析* dataType:数据类型:字符型(text) | 单精度浮点型(float)| 双精度浮点型(double)*//*** 物模型方法* 	thing.event.property.post   (主动上报) *  thing.service.property.get  (属性获取) *  thing.service.property.set  (属性设置) *  thing.service.${identifier} (动作调用)*/
const METHOD = {post: 'thing.event.property.post',get: 'thing.service.property.get',set: 'thing.service.property.set',action: 'thing.service.{identifier}',
}const FUNCTION_CODE_MAP = {//485子设备-645单相电表//485子设备-645三相电表Ua:{funCode: "02010100",long:2, dataFormat: 1, desc: 'A相电压',symbol:0},Ub:{funCode: "02010200",long:2, dataFormat: 1, desc: 'B相电压',symbol:0},Uc:{funCode: "02010300",long:2, dataFormat: 1, desc: 'C相电压',symbol:0},Ia:{funCode: "02020100",long:3, dataFormat: 3, desc: 'A相电流',symbol:1},Ib:{funCode: "02020200",long:3, dataFormat: 3, desc: 'B相电流',symbol:1},Ic:{funCode: "02020300",long:3, dataFormat: 3, desc: 'C相电流',symbol:1},Pa:{funCode: "02030100",long:3, dataFormat: 4, desc: 'A相有功功率',symbol:1},Pb:{funCode: "02030200",long:3, dataFormat: 4, desc: 'B相有功功率',symbol:1},Pc:{funCode: "02030300",long:3, dataFormat: 4, desc: 'C相有功功率',symbol:1},Qa:{funCode: "02040100",long:3, dataFormat: 4, desc: 'A相无功功率',symbol:1},Qb:{funCode: "02040200",long:3, dataFormat: 4, desc: 'B相无功功率',symbol:1},Qc:{funCode: "02040300",long:3, dataFormat: 4, desc: 'C相无功功率',symbol:1},Sa:{funCode: "02050100",long:3, dataFormat: 4, desc: 'A相视在功率',symbol:1},Sb:{funCode: "02050200",long:3, dataFormat: 4, desc: 'B相视在功率',symbol:1},Sc:{funCode: "02050300",long:3, dataFormat: 4, desc: 'C相视在功率',symbol:1},PFa:{funCode: "02060100",long:2, dataFormat: 3, desc: 'A相功率因数',symbol:1},PFb:{funCode: "02060200",long:2, dataFormat: 3, desc: 'B相功率因数',symbol:1},PFc:{funCode: "02060300",long:2, dataFormat: 3, desc: 'C相功率因数',symbol:1},FPEnergy:{funCode: "00010000",long:4, dataFormat: 2, desc: '正向有功总电能',symbol:0},OPEnergy:{funCode: "00020000",long:4, dataFormat: 2, desc: '反向有功总电能',symbol:0},FPEnergy1:{funCode: "00010100",long:4, dataFormat: 2, desc: '尖时段有功总电能',symbol:0},FPEnergy2:{funCode: "00010200",long:4, dataFormat: 2, desc: '峰时段有功总电能',symbol:0},FPEnergy3:{funCode: "00010300",long:4, dataFormat: 2, desc: '平时段有功总电能',symbol:0},FPEnergy4:{funCode: "00010400",long:4, dataFormat: 2, desc: '谷时段有功总电能',symbol:0},FPEnergyA:{funCode: "00150000",long:4, dataFormat: 2, desc: 'A相正向有功电能',symbol:0},FPEnergyB:{funCode: "00290000",long:4, dataFormat: 2, desc: 'B相正向有功电能',symbol:0},FPEnergyC:{funCode: "003D0000",long:4, dataFormat: 2, desc: 'C相正向有功电能',symbol:0},OPEnergyA:{funCode: "00160000",long:4, dataFormat: 2, desc: 'A相反向有功电能',symbol:0},OPEnergyB:{funCode: "002A0000",long:4, dataFormat: 2, desc: 'B相反向有功电能',symbol:0},OPEnergyC:{funCode: "003E0000",long:4, dataFormat: 2, desc: 'C相反向有功电能',symbol:0},//Pdmd:{funCode: "02800004",long:3, dataFormat: 4, desc: '有功需量',symbol:1},//Qdmd:{funCode: "02800005",long:3, dataFormat: 4, desc: '无功需量',symbol:1},GridFreq:{funCode: "02800002",long:2, dataFormat: 2, desc: '频率',symbol:0},Temp:{funCode: "02800007",long:2, dataFormat: 1, desc: '温度',symbol:1},P:{funCode: "02030000",long:3, dataFormat: 4, desc: '总有功功率',symbol:1},Q:{funCode: "02040000",long:3, dataFormat: 4, desc: '总无功功率',symbol:1},S:{funCode: "02050000",long:3, dataFormat: 4, desc: '总视在功率',symbol:1},PF:{funCode: "02060000",long:2, dataFormat: 3, desc: '总功率因数',symbol:1},PEnergy:{funCode: "00000000",long:4, dataFormat: 2, desc: '组合有功总电能',symbol:1},//新字段Version:{funCode: "04800001",long:20, dataFormat: 0, desc: '版本号',symbol:0,ASCII:true, dataType: "text"},TimeYMDW:{funCode: "04000101",long:4, dataFormat: 0, desc: '年月日星期',symbol:0,dataType: "text"},TimeHMS:{funCode: "04000102",long:3, dataFormat: 0, desc: '时分秒',symbol:0,dataType: "text"},}/*** 将设备的自定义格式数据转换为标准协议的数据,设备上报数据到物联网平台时调用* @param {string} jsonString "{\"data\": \"frame\", \"identifier\": \"Ua\"}"" * @param {string} jsonString.data 报文帧* @param {string} jsonString.identifier 物模型标识符* @returns {object} result* @returns {string} result.data 物模型属性值* @returns {string} result.deviceName 设备号(通讯地址)* @returns {string} result.identifier 物模型标识符* @returns {string} result.method 物模型方法 * thing.event.property.post (主动上报) | thing.service.property.get (属性获取) | thing.service.property.set (属性设置) | thing.service.${identifier} (动作调用)*///设备上报
function rawDataToProtocol(jsonString) {const jsonData = JSON.parse(jsonString)const rawData = jsonData.data// 云到设备的数据标识(这里用于校验,设备回复报文中的标识符是否正确)const identifier = jsonData.identifier//校验部分// 从站异常应答校验if (rawData.substring(16, 18) === "D1" || rawData.substring(16, 18)=== "D4") {throw new Error(`从站异常应答,报文:${rawData}`);}// 查找字符串中两个 "68" 的位置 第1-2位 和 第15-16位 必须是"68"if (rawData.substring(0, 2) !== '68') {throw new Error('第1-2位必须是"68"');}if (rawData.substring(14, 16) !== '68') {throw new Error('第15-16位必须是"68"');}const regex = /^\d+$/;// 电表号校验if (!regex.test(rawData.substring(2, 14))) {throw new Error('电表号deviceName必须是12位数字');}// cs校验 判断if (calculateChecksum(rawData.substring(0, rawData.length -4)) !== rawData.slice(-4, -2)) {throw new Error('CS校验值不正确');}// 定义输出结果:resultlet result = {deviceName:"", //设备号(通讯地址)data:"",   //读的结果返回值identifier:"",  //读的标识符method:""   //物模型方法};//----------------------------------------解析method-----------------------------------------------------------------//// 判断一下上报的是thing.service.property.get (属性获取) | thing.service.property.set (属性设置)result.method = rawData.substring(16, 18)=== "91"? METHOD['get']: rawData.substring(16, 18)=== "94"?METHOD['set']:""//----------------------------------------解析-电表号-----------------------------------------------------------------//// 截取deviceName(从第一个"68"(1-2位)到第二个"68"(15-16位)之间的部分(3-14位,12位电表号))const first68Index = rawData.indexOf("68");const second68Index = rawData.indexOf("68", first68Index + 1);const deviceNameChunks = [];const deviceNameTemp = rawData.substring(first68Index + 2, second68Index)for (let i = 0; i < deviceNameTemp.length; i += 2) {deviceNameChunks.push(deviceNameTemp.substring(i, i + 2));}// 反转数组,再拼接位字符串const reversedChunks = deviceNameChunks.reverse().join('');result.deviceName = reversedChunks; // 设备号//----------------------------------------先判断是读还是写-----------------------------------------------------------------//if(rawData.substring(16, 18) === "91"){//----------------------------------------确认funCode---------------------------------------------------//// 控制码C(17-18位):  读数据回复91H  |  写数据回复94H// L = 0x04(一个数据标识长度)+ long (设备上报的数据长度long不定)(19-20位)(L内容不固定,但是仅占用1个字节)// 所以需要从字符串中第17-20位后开始取L*2位数据:前8位表示:数据标识;后几位表示:设备上报的值//读数据需要解析数据标识;写数据不用解析数据标识,设备回复94后面 + L =00H即为成功// 数据标识8位:表示该条指令确定对哪个标识符发出指令和回复let funCode = rawData.substring(20, 28);//   console.log("上报的8位数据标识",funCode)// 将funCode字符串每两位分为一组,组成数组groupslet groups = [];for (let i = 0; i < funCode.length; i += 2) {groups.push(funCode.substring(i, i + 2));}// groups每一项减去33H (51十进制) 并转为16进制字符串let res = groups.map(group => {let value = parseInt(group, 16); // 转换为十六进制数let newValue = value - 0x33; // 减去33Hreturn newValue.toString(16).toUpperCase().padStart(2, '0'); // 转换回16进制并格式化为两位});//console.log("res",res)// 接收方需要反转;反转res数组,res转成字符串,拼接最终结果funCode = res.reverse().join('');//   console.log("拼接最终结果",funCode)//----------------------------------------根据funCode-解析数据标识---------------------------------------------------//// 判断上报数据的正负let symbol = "";   // 通过funCode遍历 FUNCTION_CODE_MAP,匹配标识符for (let key in FUNCTION_CODE_MAP) {if (FUNCTION_CODE_MAP[key].funCode === funCode) {if (key !== identifier){throw new Error(`设备上报的数据标识${key}与平台下发的数据标识${identifier}不符`);}//根据funCode-解析数据标识result.identifier = key//------------------------------------解析-上报数据------------------------------------//// long是16进制的数据长度 (具体长度取决于645协议中的定义好的数据长度,这里是在FUNCTION_CODE_MAP中准备好,用long表示)const long = convertNumber(FUNCTION_CODE_MAP[key].long,16,10)*2// 设备上报的数据值  let dataValue = rawData.substring(28, 28+long); // 按照每两位分隔字符串const arr = [];for (let i = 0; i < dataValue.length; i += 2) {arr.push(dataValue.substring(i, i + 2));}// 准备工作:反转数组,并且每个字节都减去33Hconst temp = arr.reverse();const resultArray = temp.map(hex => {// 将16进制字符串转换为十进制数const decimalValue = parseInt(hex, 16);// 减去33H(即51的十进制值)const result = decimalValue - 0x33;// 如果需要将结果转换回16进制字符串,可以使用toString(16)return result.toString(16).toUpperCase().padStart(2, '0');});// console.log("反转数组resultArray",resultArray)//----------------解析上报数据(按照ASCII解析)------------------------////判断字段是否需要使用ASCII解析if(FUNCTION_CODE_MAP[key].ASCII){// 将每个16进制字符串转换为对应的ASCII字符,.trim去除前后空格 返回给result.dataresult.data = resultArray.map(hex => {// 将16进制字符串转换为整数const decimalValue = parseInt(hex, 16);// 将整数转换为对应的ASCII字符return String.fromCharCode(decimalValue);}).join('').trim();break;}else{//----------------解析上报数据(正常解析)------------------------//// 将第一项从16进制字符串按照16进制转换(结果为十进制:80H <=> 128)const firstItemDecimal = parseInt(resultArray[0], 16);// console.log("firstItemDecimal",firstItemDecimal)// 判断第一项是否大于等于80H(128 十进制值) &&  是需要考虑正负数的标识符  ==> 负号if (firstItemDecimal >= 0x80 && FUNCTION_CODE_MAP[key].symbol ===1) {//首先可以确认上报数据符号为负号symbol = "1"// 用第一项减去80H(十进制值128)之后此时差值已变成十进制,再转成16进制const result = convertNumber(firstItemDecimal - 0x80,10,16);// 将结果转换回16进制字符串,返回给resultArray[0],并确保是两位数(结果是一位,前面补0)resultArray[0] = result.toString(16).toUpperCase().padStart(2, '0');//   console.log('resultArray[0]',result,resultArray[0]); // 输出: '00'} else {//这里不用考虑符号,直接取值//   console.log('第一项小于80H');symbol = "0"}const flippedDataValue = resultArray.join('');//console.log('flippedDataValue',flippedDataValue); //判断数据正负号:1负 0正if(symbol === "1"){//这里数据是负值,必然不是字符型(text)// 判断保留几位小数(10 ** FUNCTION_CODE_MAP[key].dataFormat)))// parseFloat转成Float型数据result.data =parseFloat("-" +( flippedDataValue / (10 ** FUNCTION_CODE_MAP[key].dataFormat))); }else{//这里需要再判断一下数据类型为字符型(text)的情况if(FUNCTION_CODE_MAP[key].dataType === "text"){result.data =flippedDataValue ; }else{// 判断保留几位小数result.data =parseFloat( flippedDataValue / (10 ** FUNCTION_CODE_MAP[key].dataFormat)); }}//console.log(temp,resultArray ,flippedDataValue);break;}}}}else if(rawData.substring(16, 18) === "94"){//设备上报,报文是0x94,则认为是写入成功result.data = "94"result.identifier = identifier}//返回构造的结果return result}/*** 将标准协议的数据转换为设备能识别的格式数据,物联网平台给设备下发数据时调用* @param {string} jsonString "{\"address\":\"1\",\"functionCode\":\"0x04\",\"params\":{\"FlowRate\":true}, \"deviceName\":\"123456789012\"}"* @param {string} jsonString.address 从机地址* @param {string} jsonString.functionCode 功能码(控制码)* @param {object} jsonString.params 标识符 key-value 对* @param {string} jsonString.deviceName 设备名称* @returns {string} rawdata 设备能识别的格式数据*///设备接收
function protocolToRawData(jsonString) {const jsonResult = JSON.parse(jsonString)const deviceName = jsonResult.deviceName || '';//下发给设备的数据标识const Key_Real_Name = Object.keys(jsonResult.params)[0]  || '';//下发给设备的实际值(目前只支持写 日期 或者 时间)const Value_Real_Name = jsonResult.params[Key_Real_Name]  || '';//==========================校验部分===================================================//const regex = /^\d+$/;// 电表号校验if (deviceName.length !== 12 || !regex.test(deviceName)) {throw new Error('电表号deviceName必须是12位数字');}// 控制码校验   读0x11 <=> 17  |  写0x14 <=> 20//将functionCode转成十进制,如果既不是读17 也不是写20 就抛错const functionCode = parseInt(jsonResult.functionCode, 16)if (functionCode !== 17 && functionCode !== 20) {throw new Error(`控制码错误${jsonResult.functionCode}`);}//当指令是写的时候:目前只支持写 日期或者时间 两个数据标识,如果是写其他的数据标识直接抛错if (functionCode === 20 && (Key_Real_Name !== "TimeYMDW" && Key_Real_Name !== "TimeHMS")) {throw new Error(`此数据标识(${Key_Real_Name})不支持写入`);}//校验 写功能,日期 的值:类型 长度 是否全部是1-9的数字if (functionCode === 20 && Key_Real_Name === "TimeYMDW" && (Value_Real_Name.length !==8 ||(typeof Value_Real_Name !== "string") || !regex.test(Value_Real_Name))) {throw new Error(`写入日期格式不正确`);}//校验 写功能,时间 的值:类型 长度 是否全部是1-9的数字if (functionCode === 20 && Key_Real_Name === "TimeHMS" && (Value_Real_Name.length !==6 ||(typeof Value_Real_Name !== "string") || !regex.test(Value_Real_Name))) {throw new Error(`写入时间格式不正确`);}METHOD['get']  (属性获取)    method需要和控制码相匹配//if (functionCode === 17  &&  jsonResult.method !== METHOD['get']) {//  throw new Error(`控制码${jsonResult.functionCode}与method${jsonResult.method}不匹配`);//}METHOD['set']  (属性设置) //if (functionCode === 20  &&  jsonResult.method !== METHOD['set']) {//  throw new Error(`控制码${jsonResult.functionCode}与method${jsonResult.method}不匹配`);//}//==========================第1-16位 "68 + 电表号(按每两位反转) + 68"====================//// Step 1: 拼接起始部分let rawData = '68';  // 第1-2位 "68"// 电表号下发需要按照每两位分隔字符串,组成数组然后整体反转数组,在拼成字符串下发(接收也是,反转之后才是电表号)const deviceNameChunks = [];for (let i = 0; i < deviceName.length; i += 2) {deviceNameChunks.push(deviceName.substring(i, i + 2));}// 反转数组,再拼接位字符串const reversedChunks = deviceNameChunks.reverse().join('');rawData += reversedChunks.padEnd(12, '0'); // 第3-14位 deviceName,若长度不足则用0填充rawData += '68'; // 第15-16位 //==========================第17-20位 控制码 + 标识符位数===============================//// Step 2:   读:11     写:14rawData += jsonResult.functionCode.substring(2, 4); //控制码:读11 ,那么直接跟数据长度L = 04if( jsonResult.functionCode.substring(2, 4) === '11'){   // 读rawData += "04"//===================读=======第21-28位 数据标识符=========================================//if (FUNCTION_CODE_MAP[Key_Real_Name]) {let funCode = FUNCTION_CODE_MAP[Key_Real_Name].funCode;let dataIdentifier = calculateDataIdentifier(funCode);rawData += dataIdentifier; } else {throw new Error('FUNCTION_CODE_MAP中不存在此数据标识符');}}else if(jsonResult.functionCode.substring(2, 4) === '14'){   // 写//控制码:写14 ,那么数据长度L =04H+04H(密码:等级+密码)+04H(操作者代码)+m(数据长度)//以日期及星期(YYMMDDWW,数据长度为4个字节)为例 L = 04H + 04H + 04H +04H = 10//以时间(hhmmss,数据长度为3个字节)为例 L = 04H + 04H + 04H +03H = 0F//密码4个字节:这里取02222222(02是操作等级,后面是密码222222)//操作者代码4个字节:这里取C0C1C2C3  (这里的8位随便取,给个默认值)//使用convertNumber将十进制=>16进制,再转成大写,结果是一位的话再前面补0let long =  convertNumber(( 4 + FUNCTION_CODE_MAP[Key_Real_Name].long + 4 + 4),10,16).toUpperCase().padStart(2, '0');rawData += long; //====================写======第21-28位 数据标识符=========================================//if (FUNCTION_CODE_MAP[Key_Real_Name]) {let funCode = FUNCTION_CODE_MAP[Key_Real_Name].funCode;let dataIdentifier = calculateDataIdentifier(funCode);rawData += dataIdentifier; } else {throw new Error('FUNCTION_CODE_MAP中不存在此数据标识符');}// 这里密码等级grade 02 是需要反转的,不过只有一个字节,所以反转之后和原来一样,但是是要+33H下发给设备const grade =  "35"   // 这里password是需要反转的,比如:密码是123456,下发给设备其实是563412,不过这里是222222,目前先不考虑,// 但是是需要每两位+33H下发给设备const password =  "555555"   // 这里operatorCode是需要按照每两位反转的,并且需要+33H下发,但是目前没有用到,所以不考虑const operatorCode =  "C0C1C2C3"rawData += ( grade + password + operatorCode)//写入的数值,这里以日期及星期为例,也需要反转,按照 "星期 日 月 年"的顺序下发给设备// 按照每两位分隔字符串const arr = [];for (let i = 0; i < Value_Real_Name.length; i += 2) {arr.push(Value_Real_Name.substring(i, i + 2));}// 准备工作:反转数组,并且每个字节都减去33Hconst temp = arr.reverse();const resultArray = temp.map(hex => {// 将16进制字符串转换为十进制数const decimalValue = parseInt(hex, 16);// 减去33H(即51的十进制值)const result = decimalValue + 0x33;// 如果需要将结果转换回16进制字符串,可以使用toString(16)return result.toString(16).toUpperCase().padStart(2, '0');});//console.log("反转数组resultArray",resultArray)rawData += ( resultArray.join(''))}//==========================第29-30位 CS校验和===========================================//// Step 3: 计算校验和let checksum = calculateChecksum(rawData);rawData += checksum; // //==========================第31-32位 固定值 "16"========================================//// Step 4: 结束固定部分rawData += '16';  // // 设备能识别的格式数据return rawData;
}// 计算校验和 cs校验
// rawDataTemp-使用CS校验位前面的临时的全部报文,算出一个字节的cs校验码
function calculateChecksum(rawDataTemp) {const result = rawDataTemp.substring(0, rawDataTemp.length);let sum = 0;for (let i = 0; i < result.length; i += 2) {sum += parseInt(result.substring(i, i + 2), 16);}sum = sum % 256;// console.log("cs校验",result,sum.toString(16).padStart(2, '0'))return sum.toString(16).padStart(2, '0').toUpperCase();
}//数据标识的报文
function calculateDataIdentifier(funCode) {let hexData = funCode.match(/.{2}/g).map(x => (parseInt(x, 16) + 0x33).toString(16).padStart(2, '0')).reverse().join('');// console.log("数据标识的报文验",hexData)return hexData;
}//10进制和16进制相互转换
function convertNumber(value, fromBase, toBase) {// 检查输入是否为字符串或数字if (typeof value !== 'string' && typeof value !== 'number') {throw new Error('Input value must be a string or a number');}// 检查输入的进制是否为10或16if ((fromBase !== 10 && fromBase !== 16) || (toBase !== 10 && toBase !== 16)) {throw new Error('Base must be either 10 or 16');}// 将输入值转换为字符串const valueStr = value.toString();// 将输入值从 fromBase 转换为10进制const decimalValue = parseInt(valueStr, fromBase);// 检查转换是否成功if (isNaN(decimalValue)) {throw new Error('Invalid number format for the given base');}// 将10进制值转换为 toBaseconst convertedValue = decimalValue.toString(toBase);return convertedValue;
}

测试-例子


设备上报(设备发布,回复平台的抄读指令)///A相电压
{"data":"68000098700001689106333434356943EC16","identifier":"Ua"}
//B相电压
{"data":"68000098700001689106333534356943ED16","identifier":"Ub"}
//C相电压
{"data":"680000987000016891063336343534B32916","identifier":"Uc"}//A相电流
{"data":"68000098700001689107333435356943342216","identifier":"Ia"}
//B相电流
{"data":"68000098700001689107333535356943443316","identifier":"Ib"}
//C相电流
{"data":"68000098700001689107333635356943C5B516","identifier":"Ic"}//A相有功功率
{"data":"68000098700001689107333436356943342316","identifier":"Pa"}
//B相有功功率
{"data":"68000098700001689107333536356943443416","identifier":"Pb"}
//C相有功功率
{"data":"68000098700001689107333636356943C5B616","identifier":"Pc"}//A相无功功率
{"data":"68000098700001689107333437356943342416","identifier":"Qa"}
//B相无功功率
{"data":"68000098700001689107333537356943443516","identifier":"Qb"}
//C相无功功率
{"data":"68000098700001689107333637356973C5E716","identifier":"Qc"}//A相视在功率
{"data":"68000098700001689107333438356943342516","identifier":"Sa"}
//B相视在功率
{"data":"68000098700001689107333538356943443616","identifier":"Sb"}
//C相视在功率
{"data":"680000987000016891073336383569B3C52816","identifier":"Sc"}//A相功率因数
{"data":"6800009870000168910633343935A5452F16","identifier":"PFa"}
//B相功率因数
{"data":"68000098700001689106333539355545E016","identifier":"PFb"}
//C相功率因数
{"data":"680000987000016891063336393568CC7B16","identifier":"PFc"}//正向有功总电能
{"data":"6800009870000168910833333433CCBBAA990916","identifier":"FPEnergy"}
//反向有功总电能
{"data":"680000987000016891083333353344556677B616","identifier":"OPEnergy"}//尖时段有功总电能
{"data":"680000987000016891083334343399AABBCC0A16","identifier":"FPEnergy1"}
//峰时段有功总电能
{"data":"6800009870000168910833353433555555559516","identifier":"FPEnergy2"}
//平时段有功总电能
{"data":"680000987000016891083336343366666666DA16","identifier":"FPEnergy3"}
//谷时段有功总电能
{"data":"680000987000016891083337343377665544B916","identifier":"FPEnergy4"}//A相正向有功电能
{"data":"6800009870000168910833334833AABB99CC1D16","identifier":"FPEnergyA"}
//B相正向有功电能
{"data":"6800009870000168910833335C33CCAABB993116","identifier":"FPEnergyB"}
//C相正向有功电能
{"data":"6800009870000168910833337033AAAAAAAA2316","identifier":"FPEnergyC"}//A相反向有功电能
{"data":"6800009870000168910833334933AABB99CC1E16","identifier":"OPEnergyA"}
//B相反向有功电能
{"data":"6800009870000168910833335D33CCAABB993216","identifier":"OPEnergyB"}
//C相反向有功电能
{"data":"6800009870000168910833337133AAAAAAAA2416","identifier":"OPEnergyC"}//频率
{"data":"680000987000016891063533B335CC33BF16","identifier":"GridFreq"}
{"data":"680000987000016891063533B33533CCBF16","identifier":"GridFreq"}//温度
{"data":"680000987000016891063A33B335AACC3B16","identifier":"Temp"}
{"data":"680000987000016891063A33B335CCAA3B16","identifier":"Temp"}
//总有功功率
{"data":"6800009870000168910733333635AABBCC7316","identifier":"P"}
{"data":"6800009870000168910733333635CCBBAA7316","identifier":"P"}
//总无功功率
{"data":"6800009870000168910733333735AABBCC7416","identifier":"Q"}
{"data":"6800009870000168910733333735CCBBAA7416","identifier":"Q"}
//总视在功率
{"data":"6800009870000168910733333835AABBCC7516","identifier":"S"}
{"data":"6800009870000168910733333835CCBBAA7516","identifier":"S"}
//总功率因数
{"data":"6800009870000168910633333935CCBBCB16","identifier":"PF"}  
{"data":"6800009870000168910633333935BBAAD516","identifier":"PF"}  
//组合有功总电能
{"data":"6800009870000168910833333333353637BC9C16","identifier":"PEnergy"}
{"data":"6800009870000168910833333333BC3736359C16","identifier":"PEnergy"}//软件版本号
{"data":"684501001123226891243433B337535353535C6B636464676563655B65636389696363856164796165636679757D3F16","identifier":"Version"}
//时间
{"data":"6845010011232268910735343337737A490D16","identifier":"TimeHMS"}
//日期及星期
{"data":"6845010011232268910834343337385A45570516","identifier":"TimeYMDW"}//设备接收(平台下发指令去抄读)///{"deviceName":"119903769212","params":{"PF":true},"address":"","method":"thing.service.property.get","functionCode":"0X11"}       //645电表产品-子设备  PK  
//645电表产品-子设备  DN  
//租户id
// 想抄读的属性标识符{"productKey":"CJByFt0I3NF",    	"deviceName":"000098700001",	"type": 0,						"functionCode": "0x11","tenantId": "7zt3ng7xjk",		"params": { "Ua": true },     "identifier": "ReadData"
}protocolToRawData('{"deviceName":"119903769212","params":{"PF":true},"address":"","method":"thing.service.property.get","functionCode":"0X11"}')rawDataToProtocol('{"data":"6845010011232268910733333735C459B3A616","identifier":"Q"}')
rawDataToProtocol('{"data":"6845010011232268910733333735C459D3C616","identifier":"Q"}')/时间-读///{"productKey": "aITqSMsV7nN","deviceName": "222311000145","type": 0,"functionCode": "0x11","tenantId": "3atjs4bym3","params": { "TimeHMS": true },"identifier": "ReadData"
}/时间-写///{"productKey": "aITqSMsV7nN","deviceName": "222311000145","type": 1,"functionCode": "0x14","tenantId": "3atjs4bym3","params": { "TimeHMS": "121212" },"identifier": "TimeHMS"
}/日期-读///
{"productKey": "aITqSMsV7nN","deviceName": "222311000145","type": 0,"functionCode": "0x11","tenantId": "3atjs4bym3","params": { "TimeYMDW": true },"identifier": "ReadData"
}/日期-写///{"productKey": "aITqSMsV7nN","deviceName": "222311000145","type": 1,"functionCode": "0x14","tenantId": "3atjs4bym3","params": { "TimeYMDW": "24122503" },"identifier": "TimeYMDW"
}

 小结

        如果能重新再写一次,我想这个解析脚本应该会可以写的再好一点。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词