yaacov / node-modbus-serial

A pure JavaScript implemetation of MODBUS-RTU (and TCP) for NodeJS
ISC License
640 stars 241 forks source link

CRC error when using writeRegisters #322

Open dbmanny18 opened 4 years ago

dbmanny18 commented 4 years ago

Hello,

I am using pymodbus library to have a running modbus RTU server on one computer. With another computer I am using the node-modbus-serial library and trying to write. The reads work fine, and the write works 1/100 times. Most of the time it times out(if i have the timeout set), otherwise it just hangs there and doesn't go to my .then() statement. I get the CRC error on the server side. Any help would be appreciated.

// server.js

// set up ========================
var express  = require('express');
var http = require('http');
var path = require('path');
var app      = express();                               // create our app w/ express
var mongoose = require('mongoose');                     // mongoose for mongodb
var morgan = require('morgan');             // log requests to the console (express4)
var bodyParser = require('body-parser');    // pull information from HTML POST (express4)
var methodOverride = require('method-override'); // simulate DELETE and PUT (express4)

var ModbusRTU = require("modbus-serial");
var client = new ModbusRTU();
// client.connectRTUBuffered("/dev/tty.usbserial-FTUBDOLK", {baudRate: 9600, dataBits: 8, parity: 'even', stopBits: 1, debug: true, autoOpen: false})
client.connectRTU("/dev/tty.usbserial-FTUBDOLK", {baudRate: 9600, dataBits: 8, parity: 'even', stopBits: 1, debug: true, autoOpen: false})

// Global variables
let modbusData = null;

async function read(startingAddr, numOfRegisters) {
  await client.readHoldingRegisters(startingAddr, numOfRegisters)
    .then((data) => {
        if(data) {
            console.log('Read Data: ', data.data);
            modbusData = data.data;
            client.close();
            return;
        }
    })
    .catch((e) => {
        console.log('Error Message: ', e);
        setTimeout(() => {
          read();
        }, 3000)

    })
};

async function write(startingAddr, arrayOfData){
  let thisArray = [0x0, 0xFFFF];
  // client.setTimeout(2000);
  await client.writeRegisters(parseInt(startingAddr), thisArray)
    .then((data) => {
      console.log('Write data: ', data);
      return;
    })
    .catch((e) => {
      console.log('Error Message: ', e);
      setTimeout(() => {
        write();
      }, 500)

    })
}

app.on('error', (err) => {
  console.error(moment().format(), 'ERROR', err);
});
app.use(express.static(__dirname));                 // set the static files location /public/img will be /img for users
app.use(morgan('dev'));                                         // log every request to the console
app.use(bodyParser.urlencoded({'extended':'true'}));            // parse application/x-www-form-urlencoded
app.use(bodyParser.json());                                     // parse application/json
app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // parse application/vnd.api+json as json
app.use(methodOverride());

app.get('/', (req, res) => {
  var options = {
    root: path.join(__dirname, '/')
  };
  return res.sendFile('dist/newTestApp/index.html', options)
  // return res.sendFile('src/index.html', options)
});

app.route('/api/modbus').get((req, res) => {
  // console.log('response: ', res);
  // let resp = client.connectRTUBuffered("/dev/tty.usbserial-FTUBDOLK", {baudRate: 9600}, read);

  var dataArray = [0x0, 0xFFFF];
  if(!client.isOpen) {
    client.open();
    client.setID(0);
    write(5, dataArray);
  } else {
    write(5, dataArray);
  }

  // console.log('modbusData: ', modbusData);
  res.send({
    modbusData
    // modbus: [{ value: '24 Volts' }, { value: '10 Amps' }],
  })
})

// listen (start app with node server.js) ======================================
app.listen(8087);
console.log("App listening on port 8087");
yaacov commented 4 years ago

Hi, thank you for the issue :+1:

Added a need help flag, asking other people for help here.

If you find the bug and have a fix, please comment here.

yaacov commented 4 years ago

I do not think you are using await correctly, see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await

I think it should be:

try {
  var data = await client.writeRegisters(parseInt(startingAddr), thisArray)
  console.log('Write data: ', data);
} catch(e) {
  console.log('Error Message: ', e);
  setTimeout(() => {
    write();
  }, 500)
}
dbmanny18 commented 4 years ago

I do not think you are using await correctly, see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await

I think it should be:

try {
  var data = await client.writeRegisters(parseInt(startingAddr), thisArray)
  console.log('Write data: ', data);
} catch(e) {
  console.log('Error Message: ', e);
  setTimeout(() => {
    write();
  }, 500)
}

Yeah that's true, I just added the async and await at the last moment before posting this. Adding the async/await didn't do anything. It does the same thing without using async/await

yaacov commented 4 years ago

Adding the async/await didn't do anything. It does the same thing without using async/await

:smiley: please try using await as documented and see if you get different errors this time.

dbmanny18 commented 4 years ago

😃 please try using await as documented and see if you get different errors this time.

I tried and it's still no difference. When I look at my RTU server using pymodbus library, I see that when I send write, it doesn't receive the whole modbus frame every time. When it receives the whole modbus frame, it works perfectly. Most of the time it looks like it gets split and gets 2 frames and then we get the crc error because the server received something it was not expecting. I read through other issues and saw you gave someone advice to try pymodbus library and it seems pretty good, so i don't think it's a server side problem

dbmanny18 commented 4 years ago

It seems like increasing my baud rate from 9600 to 34800(highest possible value it seems like according to pymodbus library) still gives me a lot of CRC and data length errors(on the client side as well) but the success rate is much greater

yaacov commented 4 years ago

hmmm, can you try to await for the read abd write calls

dbmanny18 commented 4 years ago

I tried to do await for read and write but it was doing the same thing. I was running my code on a mac and I tried moving it to a windows 10 machine and it worked perfectly fine. I'm not sure what the problem is on the mac. I am okay now because I will just use my windows machine. However I am curing as to why it is not working properly on mac

halohsu commented 4 years ago

When my code works for a few seconds, it's a problem.

// 具体的寄存器读取事件循环
            processReadResponseLoop: function () {
                // 循环读取数据和绘图
                this.processData.processReadResponseLoop_fd = setInterval(() => {
                    this.processData.client.readHoldingRegisters(this.$store.getters.getRhrp1, this.$store.getters.getRhrp2).then((response) => {
                        // 获取到数据
                        let t = response.data[0];
                        this.currentVcValue = t;
                        if (t > this.maxValue || t < this.minValue) {
                            this.logText = '采集数据异常, 数据非法, 不在范围内:' + t;
                        }
                        // console.log("t2: " + t);
                        let i = this.convertTemperature(t);
                        // console.log("转换数据: " + i);

                        if (this.processData.lastTemperature === -1) {
                            // 如果等于-1说明是第一次,不进行任何操作
                        } else {
                            // 否则就计算数据,将计算结果存储到changeRate和temperature
                            let changeRateValue = Math.abs(this.processData.lastTemperature - i) / 50;
                            this.processData.changeRate.push([changeRateValue, i]);
                            // console.log([changeRateValue, i]);
                            this.processData.temperature.push([this.processData.currentTime / 1000, i]);
                            // console.log([this.processData.currentTime / 1000, i]);

                            // 下面是报表的表格部分字段值得计算
                            if (i === 550) {
                                this.logText = '正在计算V300..';
                                this.computeV_300_value(this.processData.currentTime / 1000);
                            }
                            if (i === 600) {
                                this.logText = '正在计算T600..';
                                this.computeT_600_value(this.processData.currentTime / 1000);
                            }
                            if (i === 400) {
                                this.logText = '正在计算T400..';
                                this.computeT_400_value(this.processData.currentTime / 1000);
                            }
                            if (i === 200) {
                                this.logText = '正在计算T200..';
                                this.computeT_200_value(this.processData.currentTime / 1000);
                            }
                        }

                        // 记录数据
                        this.processData.lastTemperature = i;

                        // 记录时间
                        this.processData.currentTime += 50;

                        // 判断是否可以更新数据
                        this.processData.currentDrawTime = Math.floor(this.processData.currentTime / 1000);
                        if (this.processData.currentDrawTimes !== this.processData.currentDrawTime) {
                            // 更新绘图区域
                            this.processData.currentDrawTimes += 1;
                            this.logText = "正在处理..." + this.processData.currentDrawTimes + '(s)';
                            this.processDrawChart();
                        }

                        // 判断是否到达规定的时间
                        if (this.processData.currentTime >= this.processData.targetTime) {
                            this.handleStop();
                            // 到达规定时间就要计算最终的表格数据
                            // 找到最大变化率及其对应的温度
                            let length = this.processData.changeRate.length;
                            let maxChangeRate = this.processData.changeRate[0][0];
                            let idx = 0;
                            for (let x = 1; x < length; x++) {
                                // 依次考察每一个数据
                                let tmp = this.processData.changeRate[x][0];
                                if (tmp > maxChangeRate) {
                                    maxChangeRate = tmp;
                                    idx++;
                                }
                            }
                            this.computeTvmaxValue(maxChangeRate);
                            this.computeVmaxValue(this.processData.changeRate[idx][1]);
                        }

                    }).catch((e) => {
                        clearTimeout(this.processData.processReadResponseLoop_fd);
                        console.error(e);
                    })
                }, 50);
            },