【智能电表数据接入物联网平台实践】

智能电表数据接入物联网平台实践

  • 设备接线准备
  • 设备调试
  • 代码实现
    • Modbus TCP Client 读取电表数据
      • 读取寄存器数据转成32bit Float格式
      • 然后使用modbusTCP Client 读取数据
    • 使用mqtt协议接入物联网平台
      • 最终代码实现

设备接线准备

【智能电表数据接入物联网平台实践】_第1张图片

设备调试

代码实现

Modbus TCP Client 读取电表数据

读取寄存器数据转成32bit Float格式

原理

/**
 * 
 *  17038,  7864 
参考 https://blog.csdn.net/qq_36270361/article/details/115823294

SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM
0100 0010 1000 1110 0000 1111 0101 1100

s = 0
e = (1000 0101)转10进制 133  - 127 = 6
尾数
000 1110 0000 1111 0101 1100
4#在尾数的左边有一个省略的小数点和1,这个1在浮点数的保存中经常省略,
1.000 1110 0000 1111 0101 1100
指数值e = 6,因此小数点向右移动6位,得到尾数值如下:
1000111.0 0000 1111 0101 1100

整数

1 *2^6 + 0 *2^5 + 0 *2^4 + 0 *2^3 + 1* 2^2 + 1 *2^1 + 1*2^0
64 + 0+0+0 + 4 + 2 + 1 
71
小数部分前面0太多可以忽略不记了

0 * 2^-1 + 0 * 2^-2 + 0 * 2^-3 + 0 * 2^-4 + 0 * 2^-5 ....
浮点数值 = 整数 + 小数 = 71 + 0 = 71
*/ 
function toFloat(s1, s2)
{
  // s1:第一个寄存器地址数据,s2:第二个寄存器地址数据
    //将输入数值short转化为无符号unsigned short
    const us1 = s1, us2 = s2; // int
    if (s1 < 0) us1 += 65536;
    if (s2 < 0) us2 += 65536;
    //sign: 符号位, exponent: 阶码, mantissa:尾数
    let sign, exponent; // int
    let mantissa; // float
    //计算符号位
    sign = parseInt(us1 / 32768); // js中只需要整数
    //去掉符号位
    let emCode = us1 % 32768; // int
    //计算阶码
    exponent = parseInt(emCode / 128);
    //计算尾数
    mantissa = (emCode % 128 * 65536 + us2) / 8388608; // float
    //代入公式 fValue = (-1) ^ S x 2 ^ (E - 127) x (1 + M)
    const S = Math.pow(-1, sign)
    const E = Math.pow(2, exponent - 127)
    const M = (1 + mantissa)
    return S * E * M;
}

然后使用modbusTCP Client 读取数据

// create an empty modbus client
const ModbusRTU = require("modbus-serial");
const client = new ModbusRTU();

// open connection to a tcp line
client.connectTCP("10.0.0.251", { port: 24 });
client.setID(1);
// read the values of 10 registers starting at address 0
// on device number 1. and log the values to the console.
setInterval(() => {
  console.log('-----read-----')
    client.readHoldingRegisters(4157, 10, (err, data) =>{
    // data: {
    //  data: [17038,  7864]
    //  buffer // buffer 数据 实际上转换出来就是data数组
    // } 
        if (data?.data){
          console.log(data.data);
          const powerData = toFloat(data.data[0], data.data[1])
          console.log('-------powerData------', powerData)
        }
    });
}, 3000);


使用mqtt协议接入物联网平台

const mqtt = require("mqtt");
const md5 = require('js-md5');

const secureId = "admin";
const secureKey = "adminkey";
const timestamp = new Date().getTime()
const username = `${secureId}|${timestamp}`
const password = md5(username + "|" + secureKey)
const config = {
  url: "mqtt://10.0.0.108:1883",
  productId: '1696816545212956672',
  clientId: "1704681506453053440", // 电表设备id
  host: '10.0.0.108',
  port: 1883
}

const mqttClient = mqtt.connect({
  clientId: config.clientId,
  username,
  password,
  host: config.host,
  port: config.port,
  protocol: 'mqtt'
}); //指定服务端地址和端口


// 推送数据
function publishData (key, value) {
  const msg  = {
    "deviceId": config.clientId,
    "properties": {
      [key]: value
    }
  }
  mqttClient.publish(`/${config.productId}/${config.clientId}/properties/report`,JSON.stringify(msg))
}

//连接成功
mqttClient.on("connect", function() {
  console.log("服务器连接成功");
  publishData('online_time', new Date().getTime()) // 上报一条上线的消息

});

最终代码实现

function toFloat(s1, s2)
{
  // s1:第一个寄存器地址数据,s2:第二个寄存器地址数据
    //将输入数值short转化为无符号unsigned short
    const us1 = s1, us2 = s2; // int
    if (s1 < 0) us1 += 65536;
    if (s2 < 0) us2 += 65536;
    //sign: 符号位, exponent: 阶码, mantissa:尾数
    let sign, exponent; // int
    let mantissa; // float
    //计算符号位
    sign = parseInt(us1 / 32768); // js中只需要整数
    //去掉符号位
    let emCode = us1 % 32768; // int
    //计算阶码
    exponent = parseInt(emCode / 128);
    //计算尾数
    mantissa = (emCode % 128 * 65536 + us2) / 8388608; // float
    //代入公式 fValue = (-1) ^ S x 2 ^ (E - 127) x (1 + M)
    const S = Math.pow(-1, sign)
    const E = Math.pow(2, exponent - 127)
    const M = (1 + mantissa)
    return S * E * M;
}
// create an empty modbus client
const ModbusRTU = require("modbus-serial");
const client = new ModbusRTU();

// open connection to a tcp line
client.connectTCP("10.0.0.251", { port: 24 });
client.setID(1);


const mqtt = require("mqtt");
const md5 = require('js-md5');

const secureId = "admin";
const secureKey = "adminkey";
const config = {
  url: "mqtt://10.0.0.108:1883",
  productId: '1696816545212956672',
  clientId: "1704681506453053440", // 电表设备id
  host: '10.0.0.108',
  port: 1883
}
let mqttClient = null
let reconnectInterval = 1000;
let reconnectTimer = null;


// 推送数据
function publishData (key, value) {
  const msg  = {
    "deviceId": config.clientId,
    "properties": {
      [key]: value
    }
  }
  mqttClient?.publish(`/${config.productId}/${config.clientId}/properties/report`,JSON.stringify(msg))
}


function createClient() {
  if(mqttClient){
    return;
  }
  const timestamp = new Date().getTime()
  const username = `${secureId}|${timestamp}`
  const password = md5(username + "|" + secureKey)
  mqttClient = mqtt.connect({
    clientId: config.clientId,
    username,
    password,
    host: config.host,
    port: config.port,
    protocol: 'mqtt',
  }); //指定服务端地址和端口


  
  //连接成功
  mqttClient?.on("connect", function() {
    console.log("服务器连接成功");
    publishData('online_time', new Date().getTime())
  });

  // 断线重连
  mqttClient.on('error', (error) => {
    console.log('error:',new Date().getTime(), error);
    reconnect();
  });

  mqttClient.on('end', () => {
    console.log('end-------:', new Date().getTime());
    reconnect();
  });
}

function reconnect() {
  console.log(`reconnecting in ${reconnectInterval}ms...`);
  reconnectTimer = setTimeout(createClient, reconnectInterval);
  reconnectInterval = Math.min(reconnectInterval * 2, 30000);
}

// 创建链接
createClient()




// read the values of 10 registers starting at address 0
// on device number 1. and log the values to the console.
setInterval(() => {
  console.log('-----read-----')
    client.readHoldingRegisters(4157, 2, (err, data) =>{
        if (data?.buffer){
          console.log(data.data);
          const powerData = toFloat(data.data[0], data.data[1])
          console.log('------powerData-------', powerData)
          publishData('total_working_energy', powerData)
        }
    });
},5 * 60 * 1000);

效果预览
【智能电表数据接入物联网平台实践】_第2张图片

你可能感兴趣的:(物联网,node.js,MQTT,ModbusTcp)