Security News
cURL Project and Go Security Teams Reject CVSS as Broken
cURL and Go security teams are publicly rejecting CVSS as flawed for assessing vulnerabilities and are calling for more accurate, context-aware approaches.
omron-fins
Advanced tools
This is an implementation of the OMRON FINS protocol using Node.js. This library allows for rapid development of network based services that need to communicate with FINS capable devices. Utilizing the awesome asynchronous abilities of Node.js communication with large numbers of devices is very fast. UDP was chosen as the first variant of the protocol to be implemented because of its extremely low overhead and performance advantages. Although UDP is connectionless this library makes use of software based timeouts and transaction identifiers to allow for better reliability.
This adaption of the library utilises a sequence manager to coordinate callbacks with data responses, providing the ability to clearly understand who called for data when the request returns. All of the commands (listed below) can be called not only with a callback (for deremining who called) but can also except a tag
of any type (typically an object or key) permitting further routing in the users callback. If the callback is ommited, the approriate reply/timeout/error is emitted instead.
This release (and possibly future releases upto V1.0.0) has breaking changes.
Where possible, I make every attempt to keep things compatible, but sometimes, it becomes obvious a better way is worth the trouble - it happens (sorry) :)
Semantic Versioning 2.0.0 will be followed after V1 however for now, where you see V0.x.y
...
x
= major / minor changey
= patch / bugfixAs an example we will be making a directory for our example code and installing the module there:
mkdir helloFins
cd helloFins
npm init
npm install omron-fins
Requiring the library:
var fins = require('omron-fins');
Create a FinsClient
object and pass it:
port
- FINS UDP port number as set on the PLCip
- IP address of the PLCoptions
- An object containing necessary parameters timeout
, DNA
, DA1
, DA2
, SNA
, SA1
, SA2
var options = {timeout: 5000, SA1: 2, DA1: 1};
var IP = '192.168.0.2';
var PORT = 9600;
var client = fins.FinsClient(PORT, IP, options);
Add a reply listener. Response object content will vary depending on the command issued. However all responses are guaranteed to contain the following information:
.sid
- Transaction identifier. Use this to track specific command/ response pairs..command
- The issued command code..response
- The response code returned after attempting to issue a command..remotehost
- The IP address the response was sent from.client.on('reply',msg){
console.log('SID: ', msg.sid);
console.log('Command Code: ', msg.command);
console.log('Response Code: ', msg.response);
console.log('Remote Host: ', msg.remotehost);
});
Finally, call any of the supported commands!
Memory Area Read Command
address
- Memory area and the numerical start addressregsToRead
- Number of registers to readcallback
- Optional callback methodtag
- Optional tag item to send in callback method /* Reads 10 registers starting from register 00000 in the DM Memory Area */
.read('D00000',10);
/* Same as above with callback */
client.read('D00000',10,function(err,bytes) {
console.log("Bytes: ", bytes);
});
Memory Area Write Command
address
- Memory area and the numerical start addressdataToBeWritten
- An array of values or single valuecallback
- Optional callback methodtag
- Optional tag item to send in callback method/* Writes single value of 1337 into DM register 00000 */
.write('D00000',1337)
/* Writes the values 12,34,56 into DM registers 00000 00001 000002 */
.write('D00000',[12,34,56]);
/* Writes the values 12,34,56 into DM registers 00000 00001 000002 and callsback when done */
.write('D00000',[12,34,56], function(seq){
//check seq.timeout and seq.error
console.log(seq.response)
});
/* Same as above with callback */
.write('D00000',[12,34,56],function(err, seq) {
console.log("seq: ", seq);
});
Memory Area Fill Command
address
- Memory area and the numerical start addressdataToBeWritten
- Two bytes of data to be filledregsToBeWritten
- Number of registers to writecallback
- Optional callback methodtag
- Optional tag item to send in callback method
/* Writes 1337 in 10 consecutive DM registers from 00100 to 00110 */
.fill('D00100',1337,10);
/* Sames as above with callback */
.fill('D00100',1337,10,function(err, seq) {
console.log("seq: ", seq);
});
RUN
callback
Optional callbacktag
- Optional tag item to send in callback method/* Puts into Monitor mode */
.run(function(err, seq) {
//
});
STOP
callback
Optional callbacktag
- Optional tag item to send in callback method
/* Stops program excution by putting into Program mode */
.stop(function(err, seq) {
});
.stop();
STATUS
callback
Optional callbacktag
- Optional tag item to send in callback method.status(function(err, seq) {
console.log(err, seq)
}, tag);
.status();
======
Bare bones example that will show you how to read data from a single client.
var fins = require('../lib/index');
//var fins = require('omron-fins');
// Connecting to remote FINS client on port 9600 with default timeout value.
// PLC is expected to be at 192.168.0.2 and this PC is expected to be fins node 1
var client = fins.FinsClient(9600,'192.168.0.2', {SA1:1, DA1:1});
// Setting up our error listener
client.on('error',function(error, seq) {
console.log("Error: ", error, seq);
});
// Setting up our timeout listener
client.on('timeout',function(host, seq) {
console.log("Timeout: ", host);
});
// Setting up the genral response listener
// Showing a selection of properties of a sequence response
client.on('reply',function(seq) {
console.log("Reply from : ", seq.response.remoteHost);
console.log("Sequence ID (SID) : ", seq.sid);
console.log("Operation requested : ", seq.request.functionName);
console.log("Response code : ", seq.response.endCode);
console.log("Response desc : ", seq.response.endCodeDescription);
console.log("Data returned : ", seq.response.values || "");
console.log("Round trip time : ", seq.timeTaken + "ms");
console.log("Your tag: ", seq.tag);
});
// Read 10 registers starting at DM register 0
// a "reply" will be emitted - check general client reply on reply handler
client.read('D0',10);
// Read 10 registers starting at DM register D700 & callback with my tagged item upon reply from PLC
// direct callback is usefull for getting direct responses to direct requests
var cb = function(err, seq) {
console.log("############# DIRECT CALLBACK #################")
if(err)
console.error(err);
else
console.log(seq.request.functionName, seq.response.values);
console.log("###############################################")
};
client.read('D700',10, cb, new Date());
//example fill D700~D704 with 123
client.fill('D700',123, 5);
//example tagged data for sending with a status request
var tag = {"source": "system-a", "sendto": "system-b"};
client.status(function(err, seq) {
if(err) {
console.error(err);
} else {
//use the tag for post reply routing
console.log(seq.tag, seq.response);
}
}, tag);
TODO: Test and update this demo following v0.2.0 breaking changes
Example of instantiating multiple objects to allow for asynchronous communications. Because this code doesn't wait for a response from any client before sending/receiving packets it is incredibly fast. In this example we attempt to read a memory area from a list of remote hosts. Each command will either return with a response or timeout. Every transaction will be recorded to the responses
array with the ip
as a key and the seq.response.values
as the associated value.
If a timeout occurs and you have provided a callback, the seq.timeout
flag will be set.
If a timeout occurs and you have not provided a callback, to can get a response by listening for 'timeout'
being emitted.
Once the size of the responses array is equal to the number of units we tried to communicate with we know we have gotten a response or timeout from every unit
/* ***************** UNTESTED ***************** */
var fins = require('omron-fins');
var debug = true;
var clients = [];
var responses = {};
/* List of remote hosts can be generated from local or remote resource */
var remoteHosts = [
{ KEY: "PLC1", IP:'192.168.0.1', OPTS: {DA1:1, SA1:99} },
{ KEY: "PLC2", IP:'192.168.0.2', OPTS: {DA1:2, SA1:99} },
{ KEY: "PLC3", IP:'192.168.0.3', OPTS: {DA1:3, SA1:99} },
];
/* Data is ready to be processed (sent to API,DB,etc) */
var finished = function(responses) {
console.log("All responses and or timeouts received");
console.log(responses);
};
var pollUnits = function() {
/* We use number of hosts to compare to the length of the response array */
var numberOfRemoteHosts = remoteHosts.length;
var options = {timeout:2000};
for (var remHost in remoteHosts) {
/* Add key value entry into responses array */
clients[remHost.KEY] = fins.FinsClient(9600,remHost.IP,remHost.OPTS);
clients[remHost.KEY].on('reply', function(seq) {
if(debug) console.log("Got reply from: ", seq.response.remotehost);
/* Add key value pair of [ipAddress] = values from read */
responses[seq.response.remotehost] = seq.response.values;
/* Check to see size of response array is equal to number of hosts */
if(Object.keys(responses).length == numberOfRemoteHosts){
finished(responses);
}
});
/* If timeout occurs log response for that IP as null */
clients[remHost.KEY].on('timeout',function(host, seq) {
responses[host] = null;
if(Object.keys(responses).length == numberOfRemoteHosts){
finished(responses);
};
if(debug) console.log("Got timeout from: ", host);
});
clients[remHost.KEY].on('error',function(error, seq) {
//depending where the error occured, seq may contain relevant info
console.error(error)
});
/* Read 10 registers starting at DM location 00000 */
clients[remHost.KEY].read('D00000',10);
};
};
console.log("Starting.....");
pollUnits();
If you have Wirshark installed it is very simple to analyse OMRON FINS/UDP traffic:
Simply select your network interface and then hit "Start"
Once in Wireshark change your filter to "omron"
Now you can examine each FINS packet individually
FAQs
Node.js implementation of the Omron FINS protocol
The npm package omron-fins receives a total of 106 weekly downloads. As such, omron-fins popularity was classified as not popular.
We found that omron-fins demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
cURL and Go security teams are publicly rejecting CVSS as flawed for assessing vulnerabilities and are calling for more accurate, context-aware approaches.
Security News
Bun 1.2 enhances its JavaScript runtime with 90% Node.js compatibility, built-in S3 and Postgres support, HTML Imports, and faster, cloud-first performance.
Security News
Biden's executive order pushes for AI-driven cybersecurity, software supply chain transparency, and stronger protections for federal and open source systems.