Read device by RS485 ASCII

Hi everyone,
First, I'm sorry for my english, I'm from Poland and technical language is little bit hard for me, but I will try to describe my problem very precisely.
I got device, which shows current water flow and have two totalisers. It has an RS485 port and uses the ASCII protocol (it's not ModBus). Thanks to "Hercules" program is possible to read actual flow by using this command: 81D where "81" is number of device and "D" causes the device to know what we are asking. Request for totalisers looks like this: 81L

In the attachments I show response from device. On the first picture I marked the value by a red rectangle that I want to read, on second picture I did the same, but there are two rectangles, each is individual totaliser.
Now, is it possible to create a node (I don't know how call it), which could read this device using "...", separate the values, which are required? The best option would be, that these values (marked by rectangles) could be share on ModBus TCP registers for my SCADA system. I've got Raspberry Pi and RS485 to USB converter so there is no problem to do this.
Once again sorry for my english
I'm sure there are many helpful peoples :wink:
Greeting, Robert

Hi. And welcome to the forum. I must say your English is very good and this is very well detailed for a first post. :clap:

Firstly, what you're asking is all very easily possible in node-red.

I see you are running this on windows so if you want you can continue to do so for now.

Your first step should be to get Comms going manually (automate it later)

In node-red, add an inject and set the output to a buffer and send the same send string (but in byte format) to a serial request node. Then wire that to a debug and check you get the correct reply.

Once you have that going, come back and I'll help you automate it and eventually output formatted real values to modbus or opcua or MQTT or all at once :slight_smile:

Some tips....
ESC is 27 (or 1B hex)
CR is 13 (or 0D)
See an ASCII chart for other characters or use the string to buffer conversation in the inject node)

Thanks for reply, I'm trying to do what you wrote, but there is something wrong, because, I've got syntax_error, err_timeout or undefined. If I get that what I need, I will let you know. In manual this device is advice, that say "the command consists of the character ESC (1B hex), two signs device address (first older), "n" signs reference and end sign CR (0D hex)". I'm sure this is a little bit understandable. As I told if I get what I need, I let you know. Thanks for your help :slightly_smiling_face:

Firstly, ensure other applications are closed (so that the com port is released).

Next, based on the screen shot, you only need to send ESC 81D CR. Which should be a buffer of [27,56,59,68,13]

There's something, but in buffer should be "[27,56,49,68,13]", in debug is answer "FP210v20 81 200515230242 209.9", so it's good :slight_smile:
Now, should I try to read totalisers, or we could do something with last value (209.9)?
EDIT
It's weird, because even I got an answer, there is timeout error, but who cares :joy:

So don't use 2 com nodes, feed the buffer from the 2 injects to one com.

Next task.

Add an individual topic to each inject node. Something like 81L and 81D.

Then connect the output of the com to a function node.

Inside the function node add the following...

if (msg.topic == "81D"){
  node.warn("success - I got 81D")
} else if(msg.topic == "81L") {
   node.warn("success - I got 81L")
}
return msg;

See if you get the messages in the debug window.

Yes, it's working.

Now, I just started use "split" and in "Split using" I select Fixed length of 25, because in this length are values, which I don't need. Overall answer length is 31 marks. Obviously this concerns flow value. For totalisers answer has 40 signs, but I don't need first 20 marks, but last 20 marks I want split in a half. In addition, here are two "packs" containig zeros, is there possible that hide that zeros?

Of course.

So, now lets change 2 things...

  1. Set the debug node on the output of the function to show complete message
  2. Edit the function as below
msg.payloadOrig = msg.payload; //keep original payload - for later debugging
if (msg.topic == "81D"){
   node.send({
     msg.topic: topic,
     payload: msg.payload.slice(28,35);
   });

} else if(msg.topic == "81L") {
   node.send({
     msg.topic: "81L/" + red,
     payload: msg.payload.slice(20,39);
   });
   node.send({
     msg.topic: "81L/" + blue,
     payload: msg.payload.slice(30,39);
   });
} else {
  node.warn("topic '" + msg.topic + "' not recognised");
}

return null;

NOTE
You will need to adjust the numbers in the slice() functions accordingly so that you capture the whole value (including any leading spaces and zeros)

After you get that working, we'll format the data correctly.

Something is wrong with this code, but I don't know why. However, there's too late for me to work with this and I need some sleep, but tommorow I think we could finnish this job (only if you want to help me obviously :upside_down_face: )



At this time thank you for your help and time :wink:

Oops - Typo.

msg.payloadOrig = msg.payload; //keep original payload - for later debugging
if (msg.topic == "81D"){
   node.send({
     topic: msg.topic,
     payload: msg.payload.slice(28,35);
   });

} else if(msg.topic == "81L") {
   node.send({
     topic: "81L/red",
     payload: msg.payload.slice(20,39);
   });
   node.send({
     topic: "81L/blue",
     payload: msg.payload.slice(30,39);
   });
} else {
  node.warn("topic '" + msg.topic + "' not recognised");
}

return null;

Dont forget ....
You will need to adjust the numbers in the slice() functions accordingly so that you capture the whole value (including any leading spaces and zeros)

After you get that working, we'll format the data correctly.

Okay, I got the values what I need, but I have got to modify your code a little bit, here is it:

msg.payloadOrig = msg.payload; //keep original payload - for later debugging
if (msg.topic == "81L"){
   node.send({
     topic: msg.topic,
     payload: msg.payload.slice(25,31)
   });

} else if(msg.topic == "81D") {
   node.send({
     topic: "81D/red",
     payload: msg.payload.slice(20,30)
   });
   node.send({
     topic: "81D/blue",
     payload: msg.payload.slice(30,40)
   });
} else {
  node.warn("topic '" + msg.topic + "' not recognised");
}

return null;

In this case in debug page I got this:

Don't worry about the same value at "81D/red" and "81D/blue", it's good

Excellent - so now to make proper numbers

modify the function once more and change the part that slices the string to convert to numbers.

Wrap a call to parseInt() (if its an integer) or parseFloat() (if its a float) around the source value.

e.g.

node.send({
     topic: "81D/red",
     payload: parseFloat(msg.payload.slice(20,30))
});

Lets see how that looks.

Values changed color from red to blue and the zeros are hidden in totalisers

Not sure I understand - do the values look ok?

Can you show me your code and the debug output?

Sure, values looks ok, here is screenshot:

Here is code:

msg.payloadOrig = msg.payload; //keep original payload - for later debugging
if (msg.topic == "81L"){
   node.send({
     topic: msg.topic,
     payload: parseFloat(msg.payload.slice(25,31))
   });

} else if(msg.topic == "81D") {
   node.send({
     topic: "81D/red",
     payload: parseInt(msg.payload.slice(20,30))
   });
   node.send({
     topic: "81D/blue",
     payload: parseInt(msg.payload.slice(30,40))
   });
} else {
  node.warn("topic '" + msg.topic + "' not recognised");
}

return null;

Now, if it's possible, I want to send these values by ModBus TCP as I wrote earlier, but flow must be in Float and totalisers must be as 64-bit Integer, but I'm aware, it's too early for this :sweat_smile:

Excellent - are you happy with the progress?


Gotta go offline for an hour - please try some stuff.

  • get it working continuously be setting the trigger node to repeat mode (note, you might need to use a limit node set to space messages out or change to 1 trigger then a function node to send alternative buffers)
  • add RBE node at the end so only changed values come through

In the mean time, so that I have an idea where to take you next, what SCADA system are you using and what protocols does it support (MQTT? OPC? OPCUA?) that you might be able to use?

YESSS, I'm so happy :smiley:

Of course, I will try to do something by myself, just wanted to ask, when I could do by myself :joy:

I will do my best and I afraid, I'm also go offline for few hours.
I using Asix Scada System (from ASKOM, polish company, Asix based on Siemens program). Here is list of supported protocols:
https://www.asix.com.pl/en/about_asix/communication_modules/
http://downloads.askom.com.pl/download/en/asix_9_manual/Communication_Drivers.pdf
Here are more info about our scada and protocols

For me the best option is to use ModBus TCP protocol

Unfortunately, the modbus protocol implementations in node-red (that i have used and seen) are not the most robust (i've personally seen it crash node-red as have many others).

If i were you, I would strongly consider MQTT or REST.

According to this, you can use both MQTT and REST.
More references here and here...
image

Are you familiar with either of these protocols? both are rock sold in node-red (MQTT is by far the easiest of of them all)

Okay then, let it be your way :wink:
I don't know these protocols, because we only use some of these list (like m-bus, gazmodem, modbus, etc), but I'd like to learn something new, so you're master, tell me what should I do :slightly_smiling_face:

Btw, I set the inject nodes as repeat in 30 seconds and both injects worked properly, there aren't any errors, I added RBE node, but I get the same data as before

Good - you wont be sorry - MQTT is the future :slight_smile: (and it is 100% easier than modbus etc)

It should only permit the data to pass when it changes - can you post screen shot of your flow as it stands AND your flow export (between backticks please)?

Oh, also, download MQTT Explorer ready for the next step