cmseaton42 / node-ethernet-ip Goto Github PK
View Code? Open in Web Editor NEWA Lightweight Ethernet/IP API written to interface with Rockwell ControlLogix/CompactLogix Controllers.
License: MIT License
A Lightweight Ethernet/IP API written to interface with Rockwell ControlLogix/CompactLogix Controllers.
License: MIT License
When calling the (undocumented) Controller.destroy()
function on an unconnected session, the connection and the controller's instance don't get actually destroyed, leaking the instance itself a TCP socket handle (including its file descriptor). When done multiple times, this leads to a file descriptor starvation, causing any subsequent I/O on the whole process to fail with EMFILE.
Calling Controller.destroy()
should completely destroy the instance, without leaking any instance nor file descriptors
The root cause is that Controller.destroy()
tries to write a unregister session packet before actually destroying the underlying socket. When the packet can't be written (like when the connection hasn't completed in the first place), the socket doesn't get destroyed.
Some possible solutions:
close()
function: The Socket.destroy()
function, according to the Node.JS API, is meant to be called when we want to ultimately kill the socket. The Socket.close()
is meant to gracefully close the connection. This node could follow the standard having a Controller.close()
for gracefully closing the connection (like writing the unregister session packet and sending TCP FIN), and letting Controller.destroy()
to forcefully destroy the socket and connection. This has been discussed on #53. Downside is breaking the current API.This issue has surfaced on node-red-contrib-cip-ethernet-ip when connecting to a PLC that is not always online. When the PLC is offline, the above mentioned issue happens, but as the node keeps trying to connect to the PLC (in case it is back online), a lot of file descriptors are leaked, leading to a file descriptor starvation and compromising the whole Node-RED process.
Controller
, connecting to a dummy IP address (so that it doesn't connect)Controller
instance and try again./proc/xxxx/fd
, where xxxx is the PID of the node.js process)TCP
, TCPWrapper
and Controller
instances can also be checked by using Chrome's Developer Console.npm list
- e.g. 1.0.6): 1.2.5node --version
- e.g. 9.8.0): 10.15.3I have found that mistakes occur when adding to much Tags to a TagGroup. So is there a max Size of TagGroup items depending on DataType?
We have some code to send a group of tag values:
// fooTag and barTag have been previously defined
fooTag.value = 123;
barTag.value = 456;
const outputGroup = new TagGroup();
outputGroup.add(fooTag);
outputGroup.add(barTag);
await plc.writeTagGroup(outputGroup);
In our PLC, we expect that foo and bar have both been changed for the same scan. But occasionally it seems that one tag is applied in one scan, and the other is applied later.
Again, this issue is flaky.. it seems that both tags usually get applied on the same scan, but every once in a while, it seems they don't.
Is this the expected behavior of Ethernet IP? Or are tag write groups supposed to be batched properly? Is there any way to write several tags to the PLC that will be picked up on the same scan?
The errors generated in the below lines seem to be incorrect.
node-ethernet-ip/src/controller/index.js
Line 554 in c4e1053
node-ethernet-ip/src/controller/index.js
Line 590 in c4e1053
Read/Write Tags/Groups should be more await friendly by allowing const [ error, data ] = PLC.readTag( tag )
You can currently await any of these functions but if an error happens, it throws an uncaught promise error which are pretty annoying to track down. The workaround is to write a wrapper for each function that returns a promise and catch errors yourself which makes the current level of support for await pointless.
You should be able to handle all errors like so:
const [ error, data ] = PLC.readTag( tag )
if ( error ) {
// handle the error, log error, break you current block, etc
}
Another option could be to pass an error callback but... or an options object to control return structure
Each of these functions should contain a then
and a catch
and both should return something and not cause unhandled promise rejection errors. Returning [ false, data ]
could be a breaking change however so a callback could be added to be executed on the catch
block.
I currently use await-to-js to "awaitify" these functions.
Trying to use async await much more than I used to and encountering unexpected issues or forgetting to use helper functions.
npm list
- e.g. 1.0.6):node --version
- e.g. 9.8.0):I am trying to read from a Logix5572 (firmware 31.011) and when reading an Atomic BOOL, I see that the value returned by the PLC in the data buffer at index 2 is either 0x00
for false
or 0x01
for true
.
In line 426 of src/tag/index.js the code does a hard comparison matching only 0xff
to true
This also seem to be the value written to the PLC in lines 551/552 of src/tag/index.js
I personally think that any non-zero value should be considered as true
.
Change line 426 of src/tag/index.js of from:
this.controller_value = data.readUInt8(2) === 0xff ? true : false;
to
this.controller_value = data.readUInt8(2) !== 0;
A pull request is available as #30
We are reading whether some tags in the PLC are either true
or false
, and the value returned by the library does not change when the PLC value changes
BOOL
value in the PLC (currently doing this with Logix Designer studio 5000)0
to 1
and vice versafalse
1.2.0
8.11.4
Ubuntu Linux 18.04.01
Logix5572
31.011
would this work with plc5s?
.length() is not returning the number of groups within tag
As above (node-ethernet-ip/src/tag-group/index.js)
Length of group should be returned
Change (Line 31) return Object.keys(this.tags).length;
to return Object.keys(this.state.tags).length;
* @param {Tag} tag - Tag Object to Write
Should be
* @param {Promise} - promise to complete before the timeout
Good morning
I have read on the npm website that you will soon be able to read tags for UDTs.
My question is when this functionality will be active or if there is at this time any beta version that includes this.
My question is when this functionality will be active or if there is at this time any beta version that includes this.
Thanks for your help
Changed Event is missed for previously written tags.
When a tag is written to the PLC, in the following read cycles is no Changed Event produced.
A Changed Event is also produced for tags previously written to the PLC.
In file /src/tag/index.js remove line (574):
unstageWriteRequest() {
const { tag } = this.state;
tag.stage_write = false;
//tag.controllerValue = tag.value;
}
If node-ethernet-ip is used in Node-RED and eth-ip in and eth-ip out nodes are connected to the same PLC tag, the value is properly written to the PLC but cannot be read back.
The reasons for this behaviour are:
if (newValue !== this.state.tag.controllerValue)
does not see a difference and there no Changed Event has been emitted.npm list
- e.g. 1.0.6): 1.2.5node --version
- e.g. 9.8.0): 12.16.2After calling PLC.connect, when the promises have completed, the application stays open.
The Readme doesn't indicate to expect this behavior, nor does it seem to indicate how to properly close open connections.
I tried PLC.destroy
, PLC.destroySoon
, PLC.end
, and PLC.close
. I either got errors (no function or promise rejection), or the API continues to run in the background. I tried methods inside the callback and in .finally(()=.{})
I looked through the source file for controller and EINC, I could not see a standout example of explicitly closing a socket, and recommendations for TCP sockets didn't seem to work either.
When running the info or read examples from the Readme, the console does not return to prompt when all code is complete.
The connection should close when the callback is complete, or the method for properly closing a connection should be explicitly documented.
Controller
.PLC.once(addr, socket, callback)
method, which closes after the callback is executed.PLC.close()
method that properly shuts down the scanner, workers, tcp, etc from inside and outside the callback, allowing the application to complete after the callback returns, without triggering any errors.I'm trying to bypass the vendor locked in applications we currently rely on to generate some time-series logs of important metrics. I'm in the stage of subscribing to the proper tags, and streaming the information to the console, in order to verify it before forwarding it to some sort of datastore. Noticed this issue immediately, and am concerned about the proper way to handle in order to prevent resource leaks on production machines.
1.2.3
10.16.0
7 x64
1769-L24ER-QBFC1B/A LOGIX5324ER
26.13
On a specific devices or/and particular network failures , use the destroy method to ends the devices connection will end all the process
10 Jan 11:09:35 - Error: This socket has been ended by the other party
at Controller.writeAfterFIN [as write] (net.js:407:14)
at Controller.destroy (/home/aurelien/repos/braincubeiot2-contrib-ethernetip/.bin/red/ethernetip.js:1118:14)
at destroyPLC (/home/aurelien/repos/braincubeiot2-contrib-ethernetip/.bin/red/ethernetip.js:8162:31)
Normally when a socket is gone don't try to write something on it.
Apply this changement in your destroy method like that
destroy(exception) {
const { unregisterSession } = encapsulation;
if(this.destroyed) return ;
this.write(unregisterSession(this.state.session.id), () => {
this.state.session.established = false;
super.destroy();
});
}
My connection pass through a proxy and fucked up some times. And close connections.
npm list
- e.g. 1.0.6): 6.9.0node --version
- e.g. 9.8.0): 12.2.0Calling readTagGroup
/writeTagGroup
while scanning or calling multiple readTag
/writeTag
methods in a row without the use of ASYNC/AWAIT
will be handled appropriately without the chance of tags being assigned the wrong values by mistake.
Currently, If a user were to do something like the following...
const group = new TagGroup();
group.add(new Tag("dint1"));
group.add(new Tag("dint2"));
const PLC = new Controller();
PLC.subscribe(new Tag("dint3"));
PLC.connect("192.168.1.1").then(() => {
PLC.scan();
PLC.readTagGroup(group);
});
or...
const tag1 = new Tag("dint1");
const tag2 = new Tag("dint2");
PLC.connect("192.168.1.1").then(() => {
PLC.readTag(tag1);
PLC.readTag(tag2);
});
then there is a chance that the Controller
class can step on other outgoing network requests due to the async nature of js as well as the non-descriptive structure of the CIP Read Tag Service network responses. This could cause the tags to be assigned wrong values.
Offload Read/Write responsibilities to a worker to synchronously run the requested tasks. This could be implemented as a priority queue (giving call priority to requests originating to the scan
group).
Changing PLC Scan rate has no effect.
Tags are scanned as fast as possible
Tags are scanned as fast as possible
Tags should be scanned every X ms
ethernet-ip\src\controller\index.js
line 433 - should be "await delay(this.state.scan_rate);"
npm list
- e.g. 1.0.6):node --version
- e.g. 9.8.0):After writing a tag to the PLC, tag.value becomes undefined.
Tag value get set to undefined instead of the value it had been set to.
Tag value should remain what it was set to.
tag.unstageWriteRequest references this.state.controllerValue instead of this.state.tag.controllerValue
This is the source of the undefined value.
npm list
- e.g. 1.0.6):node --version
- e.g. 9.8.0):I am loadtesting the library to a CLX L35E. I am subscribing to 1000 integer tags and 1000 float tags at 250ms scan rate to test the load capabilities of the system. I am simultaneously running multiple instances of this nodejs script to test multiple connections to the tags and compare to connections from native DASABCIP drivers in Wonderware.
I am observing the L35E's CPU utilization to be around 75% with 4 simultaneous nodejs scripts running, each one subscribed to 1000 dint and 1000 real tags.
I am comparing this with a production PLC being polled by Wonderware DASABCIP, for around 1000 tags of dint, bool, and float. The production plc is running at around 75% utilization also, but with 16 simultaneous connections (vs 4 simultaneous nodejs tasks).
Ethernet-ip library latency is very high. Even at a scan rate of 250ms, the subscription notifications only happen around every 5 seconds, even though the tags are being changed on the test plc every 100ms (so for every scan, they should have different values).
After testing for a couple of hours, the PLC's status page reports many thousands of Conn Opens and Open Errors as well as Conn Timeouts. When compared to the production PLC (running for many months with no power cycle), only a few hundred of each of these are present. See the two screenshots below.
I think the library is dropping and re-connecting too frequently. IMO the TCP connections should be left open permanently while the script is running, only reinstated if a connection error occurs. The overhead of re-establishing these connections may be introducing the aforementioned latency and higher CPU utilization. I'm not sure, however, why there are so many Conn Errors being reported, unless the old TCP connections aren't being torn down properly.
Here's a screenshot of the test PLC's status, after running tests for only a couple hours:
Here is the live PLC, running many months with 16 simultaneous connections serving at least 1000 tags via DASABCIP driver:
Please let me know how I can reduce the connection errors and improve latency in supporting around 1000 to 2000 tags without killing the PLC's CPU.
Thanks!
Tag Group Length is not working
Returns undefined
Should return length
Change this
get length() {
return Object.keys(this.tags).length;
}
To this
get length() {
return Object.keys(this.state.tags).length;
}
Recent update has stopped program working
When building an "Unconnected Send" message, there's no way of controlling the value of the timeout
parameter. The function defaults to 2000ms, but the call doesn't allow us to customize it
Currently, all connected messages are send with the fixed timeout of 2000 ms
The library user should be able to set other values to it
We could add a new constructor option that would control the timeout value, and defaulting it to the current 2000ms value
We'd like to make node-red-contrib-cip-ethernet-ip (and therefore this library too) compatible with Omron controllers. There's even an issue there about it.
Last week, a very nice guy at Omron have done some tests and have identified that Omron controllers need this value to be at least 5024ms. So, if we can make this value configurable, we could add support to Omron controllers as well.
RangeError: Index out of range (Most recent call first)
at checkOffset (buffer.js line 977 col 11)
at Uint8Array.Buffer.readUInt16LE (buffer.js line 1023 col 5)
at Object.header.parse.buf [as parse] (/opt/losant/node_modules/ethernet-ip/src/enip/encapsulation/index.js line 227 col 26)
commandCode: buf.readUInt16LE(0),
at Controller._handleDataEvent (/opt/losant/node_modules/ethernet-ip/src/enip/index.js line 240 col 41)
const encapsulatedData = header.parse(data);
at emitOne (events.js line 116 col 13)
at Controller.emit (events.js line 211 col 7)
at addChunk (_stream_readable.js line 263 col 12)
at readableAddChunk (_stream_readable.js line 250 col 11)
at Controller.Readable.push (_stream_readable.js line 208 col 10)
at TCP.onread (net.js line 601 col 20)
Add a check maybe.
Interrupts multiple reads.
Random occurrence, not exactly sure how to reproduce (know that sucks). In a three second loop reading a Group of Tags.
In newer PLCs (version >20) there is a description field in RXLogics, that saves to the PLC. Is there a way to retrieve the tag comments/description with this library?
Note: I may interchange in this issue the words description and comment, as we refer to them as comments but in RSLogix it is called description
On the tag properties, currently, there is not a description field. That would contain a comment/name for the tag.
When querying a tag, it would have a field property for the tag description.
Most of the PLCs I work with nowadays have tag comments on almost all of the tags. When using this library sometimes I would need to see what the comment is for that tag. Currently, I have to find the tag and then hunt it down in RSLogix to find the description. However, when I am in the field this can be quite cumbersome.
Currently, there is no support for tags of type String, Array, or LINT.
Array
const arr = new Tag("ArrayName[1:5]"); // To read elements 1 through 5
String
const arr = new Tag("StringName");
Lint
const arr = new Tag("LintName");
npm list
- e.g. 1.0.6): latestnode --version
- e.g. 9.8.0): 9.10.0Provide a disconnect event handler
Disconnecting the PLC from the network does not get handled natively with the library. Attempting to read or write to it causes timeouts.
It would be nice to provide a disconnect callback to make it easier cleanup old connections and attempt to reconnect.
PLC.disconnect().then( () => {
// do some connection cleanup, report offline, attempt reconnect etc
});
In order to detect whether the PLC is online, have to check for TIMEOUT errors thrown by _readTag
, _writeTag
, _readTagGroup
, and _writeTagGroup
but this requires actually reading or writing something. Some sort of defined watchdog type monitoring of the connecting would make code more concise and easier to understand.
The current limit for any given queue is the default defined in task-easy
Pass any queue length so projects controlling a larger set of data can work.
Define opts in controller constructor and instantiate queues with the passed in parameter.
We are trying to poll larger subset of data individually, and would like to be able to add more than 100 points to the task queue.
When reading some tags from custom made Add-On Instruction on PLC.scan()
it throws an error.
const PLC = new Controller();
const tags = [
new Tag("test_duty_cycle.EnableIn"),
new Tag("test_duty_cycle.I_RunRequest")
];
PLC.connect("192.168.98.1", 0).then(() => {
for (let t of tags) {
PLC.subscribe(t);
}
PLC.scan().catch((err) => {
console.log(err);
});
});
{"generalStatusCode":30,"extendedStatus":[]}"
Which says Embedded service error and no more explanation in the protocol literature.
Can be found here DUTY_CYCLE.L5X
When my code reads test_duty_cycle.EnableIn
it's ok, but reading test_duty_cycle.I_RunRequest
throws the error.
Is it a bug or I am missing something?
Add support for being able to add port number to IP address in Controller connect method.
Port number is set to 44818 and cannot be changed.
Optionally specify port after IP address in connect method.
e.g. plc.connect('192.168.1.100:5000');
Parse connect IP address string and check for port number. Use port number passed for eip connect. Default to 44818 if no port provided (no change to current operation).
Mapping different ports on a WAN to different PLCs on a LAN.
npm list
- e.g. 1.0.6):node --version
- e.g. 9.8.0):I cannot connect to a Micrologix 1100
Any operation after connect fails. Failure happens in connect.then()
(therefore apparently upon successful connection).
Message is
Error: TIMEOUT occurred while reading Controller Props.
happening in
await this.readControllerProps()
on controller/index.js, line 125
Changing the slot number does not modify the result.
Port 44818 is open
$ nmap -Pn -p 44818 192.168.150.44
Starting Nmap 7.80 ( https://nmap.org ) at 2020-10-26 19:01 PDT
Nmap scan report for 192.168.150.44
Host is up (0.0044s latency).
PORT STATE SERVICE
44818/tcp open EtherNetIP-2
Nmap done: 1 IP address (1 host up) scanned in 0.06 seconds
const { Controller } = require("ethernet-ip");
const PLC = new Controller();
PLC.connect("192.168.150.44", 0)
.then(() => {
console.log(PLC.properties);
})
.catch((error) => {
console.log(error);
});
[email protected]
Node Version v14.13.1
MacOS
Micrologix 1100 1763 L16AWA B/14.00
Instead of only allowing an IP address, allow the use of a FQDN for retrieving data.
Allows more options for PLC addresses.
use PLC.connect("1.location.address.plc.com", 0)...
as well as PLC.connect("192.168.1.10", 0)
bool var not right
in tag/index.js this.controller_value = data.readUInt8(2) === 0x01 ? true : false;
i test while the bool is true ,the return data is <buff 00 ff>
so this.controller_value = data.readUInt8(2) === 0xff ? true : false;
npm list
- e.g. 1.0.6):node --version
- e.g. 9.8.0):Tag names that start with an underscore (often used for bringing important tags to the top of the controller tag list) throw an error Error: Tagname Must be of Type <string>
Reading tags such as "_Rev" or "_dt"
const fooTag = new Tag("_dt");
I can't find it when I search for it in Manage palette. When downloading it using npm, it isn't shown anywhere?
Add a parameter to the Tag class to allow values to be updated even if the value has not changed.
Currently, if a tag value is initialized or changed, the Tag emits an Initialized or Changed event. If values are being graphed and the value has not changed, this could result in graphs looking really weird. It also could seem to the user that the data connection has been broken.
In order to keep values current, implement a KeepAlive event to periodically (but infrequently) update the stored value of the tag based on a keepAlive property of the tag.
Implement a KeepAlive event to periodically (but infrequently) update the stored value of the tag based on a keepAlive property of the tag.
Graphs that include values that don't change look weird.
Is it possible to convert this code to C#?
Trying to read tag value with Instance ID instead of symbolic name. Symbolic name works fine, but Instance ID keeps getting same error response 'Service Not Supported'.
Tested on compactlogix 1769-L32E
Instance ID: 55838
Request:
0000 f4 54 33 96 4d 73 e0 3f 49 0e 48 d9 08 00 45 00 .T3.Ms.?I.H...E.
0010 00 60 88 80 40 00 80 06 43 e0 c0 a8 56 1e c0 a8 .`[email protected]...
0020 56 c8 ec cb af 12 ff 67 2b 04 6f ac b9 5d 50 18 V......g+.o..]P.
0030 01 ff 7b e6 00 00 70 00 20 00 00 89 02 0b 00 00 ..{...p. .......
0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0050 00 00 00 00 02 00 a1 00 04 00 41 44 25 00 b1 00 ..........AD%...
0060 0c 00 06 00 4c 03 20 6b 25 00 1e da 01 00 ....L. k%.....
Response:
0000 e0 3f 49 0e 48 d9 f4 54 33 96 4d 73 08 00 45 00 .?I.H..T3.Ms..E.
0010 00 5a f3 8f 40 00 40 06 18 d7 c0 a8 56 c8 c0 a8 .Z..@[email protected]...
0020 56 1e af 12 ec cb 6f ac b9 5d ff 67 2b 3c 50 18 V.....o..].g+<P.
0030 10 00 21 a5 00 00 70 00 1a 00 00 89 02 0b 00 00 ..!...p.........
0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0050 00 00 00 00 02 00 a1 00 04 00 00 2c 9b 6e b1 00 ...........,.n..
0060 06 00 06 00 cc 00 08 00 ........
Symbolic Name: Integer2
Request:
0000 f4 54 33 96 4d 73 e0 3f 49 0e 48 d9 08 00 45 00 .T3.Ms.?I.H...E.
0010 00 64 89 44 40 00 80 06 43 18 c0 a8 56 1e c0 a8 [email protected]...
0020 56 c8 ed b7 af 12 c5 87 fc 27 83 16 d8 69 50 18 V........'...iP.
0030 02 00 69 06 00 00 70 00 24 00 00 8c 02 0b 00 00 ..i...p.$.......
0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0050 00 00 00 00 02 00 a1 00 04 00 c1 45 25 00 b1 00 ...........E%...
0060 10 00 02 00 4c 05 91 08 49 6e 74 65 67 65 72 32 ....L...Integer2
0070 01 00 ..
Response:
0000 e0 3f 49 0e 48 d9 f4 54 33 96 4d 73 08 00 45 00 .?I.H..T3.Ms..E.
0010 00 60 f4 4c 40 00 40 06 18 14 c0 a8 56 c8 c0 a8 .`.L@[email protected]...
0020 56 1e af 12 ed b7 83 16 d8 69 c5 87 fc 63 50 18 V........i...cP.
0030 10 00 70 59 00 00 70 00 20 00 00 8c 02 0b 00 00 ..pY..p. .......
0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0050 00 00 00 00 02 00 a1 00 04 00 fc ad 58 7f b1 00 ............X...
0060 0c 00 02 00 cc 00 00 00 c4 00 69 05 00 00 ..........i...
Followed exactly how to do it in Logix 5000 manual, but it won't work.
I want to use Instance ID because it is faster and could help with others who have performance issues with large number of tags
Any guess at what is going on?
When using the code in "Getting Connected", I'm getting an error while attempting to read PLC properties.
const { Controller } = require("ethernet-ip");
const PLC = new Controller();
// Controller.connect(IP_ADDR[, SLOT])
// NOTE: SLOT = 0 (default) - 0 if CompactLogix
PLC.connect("192.168.1.11", 0).then(() => {
console.log(PLC.properties);
}).catch(err => console.log(err));
{ generalStatusCode: 8, extendedStatus: [] }
node --version
v8.5.0
It looks like the issue is being caused by the readWallClock function not being supported by CompactLogix PLC's
I have a Keyence Vision system that I am trying to grab data off of (just one result number for now). I am hoping to do this without needing to attach the keyence system to a PLC, and instead just grab the data directly from my Linux machine. Is this possible with this library?
On the keyence side, looking at the EtherNet/IP configurations, it indicates that it is disconnected from the PLC, which I would expect, but I was hoping there was some way I could configure my Linux machine (running Ubuntu 16.04) to pull the data out without needing to also connect to the PLC (which we don't have, running this mostly for research purposes, not heavy-weight industrial use, yet)
Is this Possible?
Hi Everbody;
I am trying to read tags from Allen Bradley Micro 850 PLC with node-red-contrib-cip-ethernet-ip node
but I am taking this error : Error connecting to PLC: Error: TIMEOUT occurred while reading Controller Props. How Can I solve this problem.
I am trying to read DINT values, but sometimes these values are incorrect, how can I know if a value I am reading is incorrect?
I want to read values that are stored in the plc. These values are voltage and energy. The voltage values range from 427 to 429, but suddenly they go to 16187392 and again go back to normal. This seems to me a reading error
Returns extra decimal places that do not exist in PLC
Return exact value as exists in PLC
Unknown...
Values are not true to what exist in the PLC.
Package version (Use npm list
- e.g. 1.0.6):
[email protected]
Node Version (Use node --version
- e.g. 9.8.0):
v12.18.2
Operating System and version:
Ubuntu 18.04
Controller Type (eg 1756-L83E/B):
1756-L73 or 1769-L18ER/B
Controller Firmware (eg 30.11):
30.11 or 27.11, respectively
npm list
- e.g. 1.0.6):node --version
- e.g. 9.8.0):I'm not very familiar with Ethernet/IP, CIP, etc. but I know that some Rockwell/AB PLCs can enumerate - send a list of - all the tags that are available, along with some information about each tag. I know rslinx can do this. I'd like my stand-alone applications to be able to do it too.
Seems like this would be a new Controller method that actively enumerates tags (maybe with some filtering options) and returns an array or object representing a tag collection.
In the simplest case, after connecting to a PLC, you'd call getTagList or getSymbolList(options) - it would return an object similar to a TagGroup but with more info per tag.
Would be very happy to contribute code, if I can figure out the code and how to integrate it.
My company uses relatively lightweight edge devices running either Windows or Linux, and we distribute these to multiple customers. We encounter a variety of PLCs running a wide variety of programs, some well documented, some not at all. We prefer not to go on-site if we don't have to, and we don't want a complex or labor intensive setup process. I'd prefer not to rely on (or install) bulky or platform-dependent tools (not naming names but rslinx and CCW).
I want the ability to 'browse' a PLC in the field with platform-independent node code, automatically, given only its IP address.
PLC.connect("192.168.0.2", 0).then(async () => {
const fooTag = new Tag("BoolTag");
setInterval(async function(){
await PLC.readTag(fooTag);
console.log(fooTag);
}, 2500);
});
Any BOOL tag I attempt to read is always false.
Cannot read bool values, I have updated library.
npm list
- e.g. 1.0.6): 1.2.0node --version
- e.g. 9.8.0): v10.0.0When trying to read a tag and it's value, this error message is generated:
tag.generateReadMessageRequest is not a function
The error refers to ethernet-ip/src/controller/index.js
In the read and write tag methods at appx lines 480 and 513.
const MR = tag.generateWriteMessageRequest(value, size);
Unable to determine why this is happening.
src/tag.js
const regex = /^[a-zA-Z_][a-zA-Z0-9_]*([a-zA-Z0-9_]|[\d+])$/i;
npm list
- e.g. 1.0.6):node --version
- e.g. 9.8.0):Hello,
I try to connect to a PLC that has a Duagon CIP Stack embedded.
When I use Schneider PLC, everything works.
Then I tried with Node-Red ethernet-ip and get a : "Error connecting to PLC: Error: TIMEOUT occurred while reading Controller Props."
Doing a bit of Wireshark on it, and below the extract of a working Schneider Communication :
So the main difference between the two is that node-red request for a service Code 0x52 instead of 0x54 for the Schneider one.
Wireshark identifies this two services as :
Do you know why node-red is using this 0x52 instead of 0x54 ?
And is it possible to change it ?
Thanks for your help !
Unable to read anything from a control logic PLC.
Unable to display controller properties, unable to read a tag value.
When connecting to PLC, an UnhandledPromiseRejectionWarning is given.
I am able to ping the PLCs IP. (EN2TR card) I am able to go online with Studio 5000 programming software.
PLC is in Run mode.
Connection to PLC should complete, and plc properties would be written to console
npm list
- e.g. 1.0.6):node --version
- e.g. 9.8.0):4 slot rack, plc is in slot 0. EN2TR cards in slot 1 and slot 2. Slot 3 is open.
(node:14792) UnhandledPromiseRejectionWarning: #
(node:14792) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:14792) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
const { Controller } = require("ethernet-ip");
const PLC = new Controller();
// Controller.connect(IP_ADDR[, SLOT])
// NOTE: SLOT = 0 (default) - 0 if CompactLogix
PLC.connect("10.115.45.55", 0).then(() => {
console.log("Connected to PLC!");
console.log(PLC.properties);
});
Provide support for accessing Micro800 PLCs
The system is currently unable to connect to a Micro800 PLC. The connection times out when attempting to access the PLC.
Reading/writing data for Micro800 PLC's should work exactly the same as CLX and CPLX
Determine what connection parameter changes need to occur and modify or extend the PLC class to accommodate changes.
This will broaden support for AB PLC's to include the Micro800 line of PLCs.
I've tried to implement the STRING dataformat myself, as I need it.
I was filling up the buffer as a null-ending string , however, the data is not sent correctly.
Is there a specific data format for STRING ?
Should be "Path must be of type Buffer"
Event listeners added inside of a promise are not removed on reject creating a memory leak.
(node:2012) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 Multiple Service Packet listeners added. Use emitter.setMaxListeners() to increase limit
Repeated calls create new listeners without removing the old ones.
...not leak memory.
Event listener should be removed prior to rejecting.
Possibly just always remove listener as fist step in listener callback.
npm list
- e.g. 1.0.6):node --version
- e.g. 9.8.0):A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.