Giter Club home page Giter Club logo

st-node-ethernet-ip's People

Contributors

bombjackit avatar fernandoamorim1703 avatar geekmeupscotty avatar gfcittolin avatar jon-biz avatar pedrofrancescon avatar pilotcam avatar r4nd0wn avatar serafintech avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

st-node-ethernet-ip's Issues

Support SHORT_STRING data type for symbolic tag messaging

The SHORT_STRING data type is a single byte character string. It is sent with the first byte being the length, followed by the string data. Supporting symbolic (Rockwell) tags with this data type is relatively straightforward. Also add support for USINT (unsigned 8bit data) Code changes here:

https://github.com/greg9504/ST-node-ethernet-ip/tree/Add_Additional_DataTypes_Support

There was also a change for writing SINT data, the code used Buffer.writeUInt8 when I think it should have used Buffer.writeInt8.

Further testing should probably be done, as I've only be able to test using the Micro850 simulator in Connected Components Workbench.

Tested with
CCW version 22
PLC - 2080-LC50-48QWB-SIM (Micro850 Simulator, not actual hardware)

General about node-red-contrib-cip-st-ethernet-ip (because there isn't an issue button in that project)

Support for Micro800

Current Behavior

Would love for this package to support Micro800 controllers. Any attempt at a connection returns

{ generalStatusCode: 1, extendedStatus: [ 785 ] }

I've found a similar package that works with Micro800, seemingly with some small changes from other PLCs (See node-logix) but it isn't actively maintained and doesn't have support for some of the nice things built into this package like TagChanged or ControllerManager.
I'm new to this library and PLC communication in general but even if I could get a couple pointers on where these changes would go I would make a PR and add it.

Expected Behavior

Possible Solution (Optional)

Context

Steps to Reproduce (for bugs only)

Your Environment

  • Package version (Use npm list - e.g. 1.0.6):
  • Node Version (Use node --version - e.g. 9.8.0):
  • Operating System and version:
  • Controller Type (eg 1756-L83E/B):
  • Controller Firmware (eg 30.11):

Error : TIMEOUT during backend server running

Current Behavior

I am trying to make backend server with node.
It is running fine with attached program at first time but it has error after short 2 min. long 30 min.
< Error Message >
C:\react-app\prodboard\backend\node_modules\ethernet-ip\src\controller\index.js:654
throw new Error(<SCAN_GROUP>\n ${e.message});
^
Error: <SCAN_GROUP>
TIMEOUT occurred while writing Reading Tag Group.
at C:\react-app\prodboard\backend\node_modules\ethernet-ip\src\controller\index.js:654:31
at async Controller.scan (C:\react-app\prodboard\backend\node_modules\ethernet-ip\src\controller\index.js:647:13)

Your Environment

  • npm v9.8.1
  • NPM ethernet-ip 1.2.5
  • Node Version Node.js v18.17.1
  • Operating System window 10 Pro

plc_server.txt

forwardClose of IO connection may result in exception

While testing IO connections with a Banner Engineering XS26 safety controller I found that an exception would be generated during the forwardClose call.
Code change to fix is here:
https://github.com/greg9504/ST-node-ethernet-ip/tree/ioForwardCloseNoOTconnID

Current Behavior

Exception during forwardClose, while attempting to decode the OTconnID id. It seems that the client (XS26) did not send back the OTconnID in the message.

Expected Behavior

Check length of data before attempting to decode. The decoded OTconnID does not appear to be used anyway, so a default of 1 is set in this case.

Possible Solution (Optional)

        let OTconnID = 1;// id not sent back by some clients
        //some clients may not include OTconnID in forwardClose response
        //found while testing with Banner Engineering XS26 safetly controller
        if (data.length > 0) {
            OTconnID = data.readUInt32LE(0); // first 4 Bytes are O->T connection ID 
        }
        super.id_conn = OTconnID;

Context

Can not use lib with Banner XS26 for IO connections without fix.

Steps to Reproduce (for bugs only)

Setup IO connection with Banner Engineering XS26 then close connection...

function GenericEthernetIPclient() {
var ioscanner;                      // Connection Manager for IO exchange
var ioconnections = [];             //  IO connections
// open the io connection

var makeIOConnection = function {
// simplified
ioscanner = new STEthernetIp.IO.Scanner(2222, '0.0.0.0');
const ioconn = ioscanner.addConnection(config, module.rpi, addr, ioport, false);
}
...
// close the connection
    var _disconnectAll = async function () {
        const result = await _closeScannerWrapper();
        for (let ioconn of ioconnections) {
            if (ioconn) {
                ioconn.run = false;
                try {
                    console.log('closing io connection...')
                    await ioconn.tcpController.disconnect();
                    console.log('io connection closed');
                } catch (error) {
                    console.log('Error disconnecting io connection');
                    console.log(error);
                    ioconn.tcpController.destroy();
                    ioconn.tcpController._removeControllerEventHandlers();
                    console.log('forced io connection closed');
                }
                ioconn = undefined;
            }
        }
        ioconnections = [];
    }

// close the UDP listening port
var _closeScanner = function (successCallback, errorCallback) {
        try {
            if (ioscanner) {
                ioscanner.socket.close(() => {
                    ioscanner = undefined;
                    console.log('scanner closed');
                    successCallback(true);
                });
            } else {
                console.log('scanner not open, success');
                successCallback(true);
            }
        } catch (err) {
            errorCallback(false);
        }
    }
    var _closeScannerWrapper = function () {
        return new Promise((resolve, reject) => {
            _closeScanner((successResponse) => {
                resolve(successResponse);
            }, (errorResponse) => {
                reject(errorResponse);
                return;
            });
        });
    }

call makeIOConnection then later call disconnectAll.

Your Environment

  • Controller Type (eg 1756-L83E/B): Banner Engineering XS26-2DE Safety Controller
  • Controller Firmware (eg 30.11): FID1

Add typescript declaration file

Current Behavior

Typescript is unsupported as there is no @types/st-ethernet-ip which makes it difficult to work with typescript.

Expected Behavior

I should be able to either install this lib or install @types/st-ethernet-ip and get type declarations.

Possible Solution (Optional)

  • add index.d.ts to define all public types.

Context

My team is beginning to adopt this library as one of our core libs and using it is "janky" because we have to comb through source code to figure out what everything does. Adding a declaration file along with some basic documentation will make working with this library much easier.

Steps to Reproduce (for bugs only)

Your Environment

  • Package version [email protected]
  • Node Version 18.12.0
  • Operating System and version: Ubuntu 20.04.6 LTS x86_64
  • Controller Type: N/A
  • Controller Firmware: N/A

Getting error

Hi, I have an error 15 with plc subscription, PLC is a controllogix 5580 my connection to this PLC is:

const PLC = new Controller(false);

And the error ir :

{generalStatusCode: 15, extendedStatus: Array(1) }

Incorrect expansion of Structure value with BIT_STRING typed member

When structure member of type BIT_STRING is expanded in the value, its type is an array of integers rather than an array of bools.

Current Behavior

A PLC type BOOL[64] will be expanded as if it were typed DINT[2].

Expected Behavior

A PLC type BOOL[64] should be expanded into an array of bools with length 64.

Context

If the PLC programmer has chosen type BOOL[], there was a purposeful decision to use boolean values rather than integers. Reading this data out of the PLC should reflect the same type.

Steps to Reproduce (for bugs only)

  1. PLC: Create a UDT with a BOOL[n], then create a tag using this type
  2. EIP: myTag = new Structure("MyTag", null, tagList);
  3. EIP: await PLC.readTag(myTag);
  4. EIP: console.log(myTag.value.MyBits);

Your Environment

  • Package version (Use npm list - e.g. 1.0.6): 2.3.2
  • Node Version (Use node --version - e.g. 9.8.0): 14.17.5
  • Operating System and version: Windows 10
  • Controller Type (eg 1756-L83E/B): 1756-L74
  • Controller Firmware (eg 30.11): 20.19

Controller Manager not auto-reconnecting

Controller Manager does not auto-reconnect to a PLC. When reading a value, it retains the value from before the download and will not update.

Current Behavior

After a download to a PLC, tags are no longer read from that PLC.

Expected Behavior

Tags should resume polling from that PLC.

Possible Solution (Optional)

Context

Steps to Reproduce (for bugs only)

Your Environment

  • Package version (Use npm list - e.g. 1.0.6): 2.6.7
  • Node Version (Use node --version - e.g. 9.8.0):
  • Operating System and version:
  • Controller Type (eg 1756-L83E/B): 1756-L63 / 1756-L73
  • Controller Firmware (eg 30.11): 16.23 / 30.11

Code example to retrieve all tags and values

Code to retrieve all tags and values. Works only with newest version.

const eip = require('st-ethernet-ip')

let cont = new eip.Controller()

cont.connect(IP_ADDRESS)
.then(async () => {
    let tagGroup = new eip.TagGroup()
    
    for (let i = 0; i < cont.tagList.length; i++) {
        let tag = cont.newTag(cont.tagList[i].name, cont.tagList[i].program, false, cont.tagList[i].type.arrayDims)

        tagGroup.add(tag)

        if (cont.tagList[i].type.arrayDims > 0) { 
            await cont.getTagArraySize(tag)
        }  
    }

    await cont.readTagGroup(tagGroup)
    tagGroup.forEach(t => {
        console.log(t.name, t.value)
    })
})

Array of UDDT's with ControllerManager

How do you reference an element of an array of UUDT's using the ControllerManager addTag() function?

Current Behavior

This example code from the README works fine for a single integer tag.

const {ControllerManager} = require('st-ethernet-ip')

const cm = new ControllerManager();

//addController(ipAddress, slot = 0, rpi = 100, connected = true, retrySP = 3000, opts = {})
const cont = cm.addController('192.168.86.200');

cont.connect();

//addTag(tagname, program = null, arrayDims = 0, arraySize = 0x01)
cont.addTag('TheInteger')

cont.on('TagChanged', (tag, prevValue) => {
  console.log(tag.name, ' changed from ', prevValue, ' => ', tag.value)
})

cont.on('error', (e) => {
  console.log(e)
})

Expected Behavior

What is the correct syntax for adding a tag which is an element of a UDDT (or atomic) array.
cont.addTag(?????)

Possible Solution (Optional)

Is it something similar to:
cont.addTag(tagname, program = null, arrayDims = 0, arraySize = 0x01)
I have not has success with that other than getting the first element only.

Context

Ultimately I want to use this with your node-red node (node-red-contrib-cip-st-ethernet-ip).

Your Environment

  • Package version (Use npm list - e.g. 1.0.6): 2.5.0
  • Node Version (Use node --version - e.g. 9.8.0): 16.14.2
  • Operating System and version: OSX 10.15.7
  • Controller Type (eg 1756-L83E/B): 1769-L24ER-QB1B CompactLogix 5370
  • Controller Firmware (eg 30.11): 30.011

Complete list of all tag names that are valid on the controller

A user contacted me by email and wanted to see a way to get a complete list of all tag names that would valid on the controller including drilling down through arrays and structures. I came up with this solution. Would this be useful as a utility function?

const eip = require('st-ethernet-ip')

let cont = new eip.Controller()

cont.connect('192.168.121.10')
    .then(async () => {

        let directory = {}

        // Separate tags by program / controller scope
        cont.tagList.forEach( t => {
            directory[t.program] = [];
        })

        // Iterate through each scope
        for (program in directory) {
            let nameList = []
            let progValue = (program === 'null') ? null : program;
            let taglist = cont.tagList.filter(t2 => t2.program === progValue);

            // Iterate through each tag of each scope
            for (let i = 0; i < taglist.length; i++) {
                await drillDown(cont, nameList, taglist[i])
            }
            
            directory[program] = nameList
        }

        // Change 'null' name to 'Controller'
        directory['Controller'] = directory['null']
        delete directory.null

        console.log(directory)

    })

// Recursive tag name listing function
async function drillDown(cont, nameList, tagInfo, previousName) {
    let tagLength = 1;
    if (tagInfo.type.arrayDims > 0) {
        if (tagInfo.info === undefined) {
            let contTag = cont.newTag(tagInfo.name, tagInfo.program, false, 1);
            tagLength = await cont.getTagArraySize(contTag); 
        } else {
            tagLength = tagInfo.info;
        }
        for (let i = 0; i < tagLength; i++) {
            let newName
            if (previousName) {
                newName = previousName + '.' + tagInfo.name + '[' + i + ']';
            } else {
                newName = tagInfo.name + '[' + i + ']';
            }

            nameList.push(newName);

            if (tagInfo.type.structure) {
                let members = cont.templateList[tagInfo.type.code]._members;
                for (let a = 0; a < members.length; a++) {
                    await drillDown(cont, nameList, members[a], newName);
                }
            }

        }
    } else {
        let newName
        if (previousName) {
            newName = previousName + '.' + tagInfo.name 
        } else {
            newName = tagInfo.name
        }

        nameList.push(newName);

        if (tagInfo.type.structure) {
            let members = cont.templateList[tagInfo.type.code]._members;
            for (let a = 0; a < members.length; a++) {
                await drillDown(cont, nameList, members[a], newName);
            }
        }
    }
    
}

Cannot write to a tag (BOOL) unless reading from it first

Supposedly you can write to a tag without reading from it first so long as you declare the data type. This does not work.

Current Behavior

let heartbeatTag = new Tag("collectorHeartBeat", null, BOOL);
 await PLC[i][0].writeTag(heartbeatTag, true);

produces this:
2022-11-10 05:45:36Heartbeat Error: undefined
which is my catch block when the heartbeat tag write fails

Expected Behavior

Write the tag successfully

Possible Solution (Optional)

Context

Steps to Reproduce (for bugs only)

Your Environment

  • Package version (Use npm list - e.g. 1.0.6):
  • Node Version (Use node --version - e.g. 9.8.0):
  • Operating System and version:
  • Controller Type (eg 1756-L83E/B):
  • Controller Firmware (eg 30.11):

scan_rate failing at 2800 ms.

So, here I found a strange behavior and also I want to suggest one enhancement.

Whenever you create an ExtController you can also define the scan_rate trough the rpi parameter which by default is 100.

The deal with the connect() function is that you are assuming that the consumer want to scan the controller for the previously created Tags and add the event_emitters to them to instantly emit the events on the tags. This is very nice, but what about if I dont want to inmediately scan the variables in order to controll the reading in a more granular way.

One example to give you is: If I want to do a controller read on demand to a TagGroup I'd like to do it without loosing all this great features that you are already exposing... like the reconnecting and managing in a more abstract way the controllers instead of use the basic Controller.
Yet, this can be done, on demand, but still there is an ongoing background process happening due to "un asked" scans and emitting events on tags which possible I dont want to listen.

image

This abstraction is great, but we can create two different functions or allow the scan and the addTagEvents at will. This will ensure performance and not wasting resources when we dont want to listen the events of the tags.

Now.. moving on the next topic... I found that when we increate the rpi for the scan rate above 2800ms, this error is thrown:

image

and this dont tell us much.. but in anycase, there are specific scenariosn in which I dont want to constanlty read on the PLC (like the one I told you, I want some screenshot of the values and not interested on changed evfents)

Thanks in advance to read... I hope we can support this feature.

Feel free to open a PR on the original repo

Quick Question

Do you want to pull your changes to the original repository? Feel free to open a PR if you like. I can make you a maintainer so you pull your own PRs as I rarely have the time to look through code reviews these days.

Also, I am in the middle of a typescript rewrite of the repository that is much more stable (currently 100% coverage). Feel free to check that guy out as well if you like. The long term plan (assuming I ever get the time) is to fully transition to typescript.

Micro800 Controller.scan() Error

Current Behavior

I am now having some issues now with the subscription/scan methods. The following works and I can verify it is setting the Tag value in Connected Components Workbench, but when I uncomment the PLC.scan() method, with or without the other writeTag code I get an unhandled rejection error

Code:

const { Controller, Tag, EthernetIP } = require("st-ethernet-ip");
const { BOOL } = EthernetIP.CIP.DataTypes.Types;

const PLC = new Controller();

let tag1 = new Tag("TEST_TAG_1", null, BOOL);
PLC.subscribe(tag1);

PLC.connect("192.168.1.10", Buffer.from([]))
  .then(async () => {
    tag1.value = true;
    PLC.writeTag(tag1);

    // PLC.scan_rate = 50;
    // PLC.scan();
  })
  .catch((err) => {
    console.log(err);
  });

Error:

node:internal/process/promises:288
            triggerUncaughtException(err, true /* fromPromise */);
            ^

[UnhandledPromiseRejection: 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(). The promise rejected with the reason "#<Object>".] {
  code: 'ERR_UNHANDLED_REJECTION'
}

Any thoughts what might be causing that?

Cannot connect to PLC. General Status Code: 5

Current Behavior

I'm trying connect to PLC with this code:

const {Controller} = require('st-ethernet-ip')

const PLC = new Controller();

PLC.connect("192.168.1.222", 0).then(async () => {

    console.log("Connected!")
    
}).catch(async e => {
    console.log(e)
});

And I get this in the console:

{ generalStatusCode: 5, extendedStatus: [ 0 ] }

I read here: https://assets.omron.eu/downloads/manual/en/v2/w506_nx_nj-series_cpu_unit_built-in_ethernet_ip_port_users_manual_en.pdf that is a "Path destination unknown" error.

When I replace library "st-ethernet-ip" with "ethernet-ip", everything works ok. But I need this library, because of UDTs.

Can someone help?

Thank you

Expected Behavior

Connect to PLC

Steps to Reproduce

Run the code see above

Environment

  • Package version:
  • Node Version: v16.15.1
  • Operating System and version: Windows 11
  • Controller Type: Allen Bradley 5069-L330ERMS2
  • Controller Firmware: 34.011

having issues running sample codes with UnhandledPromiseRejection

I am trying to run a sample code under the heading 'Getting a List of Available Controller Tags and Structure Templates'

but I keep into running this error upon execution of this line:

PLC.connect("192.168.1.1", 0).then(async () => {...}

Uncaught Error UnhandledPromiseRejection: 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(). The promise rejected with the reason "#".
at getErrorWithoutStack (undefined:320:15)
at generateUnhandledRejectionError (undefined:339:15)
at processPromiseRejections (undefined:286:24)
at processTicksAndRejections (undefined:96:32)

Current Behavior

keep into running this error:
Uncaught Error UnhandledPromiseRejection: 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(). The promise rejected with the reason "#".
at getErrorWithoutStack (undefined:320:15)
at generateUnhandledRejectionError (undefined:339:15)
at processPromiseRejections (undefined:286:24)
at processTicksAndRejections (undefined:96:32)

upon execution of this line:
PLC.connect("192.168.1.1", 0).then(async () => {...}

Expected Behavior

return of tag list

Steps to Reproduce (for bugs only)

  1. Run the following code:
    const { Controller, TagList } = require("st-ethernet-ip");

const PLC = new Controller();

const tagList = new TagList();

PLC.connect("192.168.1.1", 0).then(async () => {

// Get all controller tags and program tags
await PLC.getControllerTagList(tagList)

// Displays all tags
console.log(tagList.tags)

// Displays all templates
console.log(tagList.templates)

// Displays program names
console.log(tagList.programs)

});

Your Environment

  • Package version (Use npm list - e.g. 1.0.6):
    โ”œโ”€โ”€ [email protected]
    โ””โ”€โ”€ [email protected]
  • Node Version (Use node --version - e.g. 9.8.0):
    v18.2.0
  • Operating System and version:
    windows 10
  • Controller Type (eg 1756-L83E/B):
    omron nx1p2
  • Controller Firmware (eg 30.11):
    1.27

Write Tags in Controller Manager?

Current Behavior

It doesn't appear like we can write to tags from a ControllerManager connection, just subscribe to tag changes. Is that the case? In our application we would like to use the long-lived connection of a ControllerManager and also be able to read/write tags

issues with safety plc

cannot connect to safety controller

Current Behavior

when I try to connect to a normal PLC, there are no issues. If I try to connect to a safety PLC (1756-L61S) I cannot establish a connection.

Expected Behavior

successfully connect without timeout.

Possible Solution (Optional)

I will have to dive deeper into the code, to check the connection, perhaps I am able to fix it myself.

Steps to Reproduce (for bugs only)

// connect with a safety in slot 7
const {ControllerManager} = require('st-ethernet-ip')
const cm = new ControllerManager();

const cont = cm.addController('192.168.20.3', slot=7);

cont.connect();

cont.addTag('testtag')

cont.on('TagChanged', (tag, prevValue) => {
console.log(tag.name, ' changed from ', prevValue, ' => ', tag.value)
})

cont.on('error', (e) => {
console.log(e)
})

Your Environment

  • Package version (Use npm list - e.g. 1.0.6): 2.4.4
  • Node Version (Use node --version - e.g. 9.8.0): latest LTS
  • Operating System and version: debian buster
  • Controller Type (eg 1756-L83E/B): 1756-L61S
  • Controller Firmware (eg 30.11): no idea

Can't read String

If i try to read string value i got error: Unrecognized Type Passed Read from Controller: 208

My code is:

const stringStructure = new Structure('A_AUTOMATIC.RunRecipeName', tagList);
try {
    await PLC.readTag(stringStructure);
    console.log(stringStructure.value);
} catch(e) {
    console.log(e);
}

EPIPE exception causes 'Maximum Callstack Size Exceeded' error

Current Behavior

On an exception, the ENIP class's destroy function attempts to write to the TCP socket, to gracefully close it. But, if the exception was caused by unexpectedly closed socket, this results in an endless loop.

Expected Behavior

The destroy function should not attempt to write to a closed socket, triggering an exception.

Possible Solution (Optional)

If the exception.code is EPIPE, don't write to the socket.

Jon-Biz@010de84

Context

I was attempting to set up node-red to work with eth-ip messaging. Whenever I closed the ethip server simulator, node-red crashed.

Steps to Reproduce (for bugs only)

  1. Set up an eth-ip connection in node-red
  2. Disconnect the server you are connected to.
  3. Alternately, start node-red with the server offline.

Your Environment

findTag in tagGroup feature.

There is a super cool feature you have expose.

image

This is nice, but you know that we need to pass a Tag Object in to it... and if for example we dont save that instance in memory but still know the name of the tag.. it implies extra logic to handle this scenarios..

having this feature passing a string variable name as parameter should be nice... and very helpful!

After automatic reconnection, tags are not readable and throw TIMEOUT error

May be related to Issue #56

Steps to reproduce:

  1. Connect to a CompactLogix PLC using:
const plc = new Controller()
plc.connect(ip_address, slot);

(At this point the plc.established property changes to true to indicate an active connection.)

  1. Wait a while and start reading tags repeatedly using plc.readTag()

  2. After tags are reading successfully, unplug the PLC's Ethernet cable, power it off, or change its' IP address, causing a loss of connectivity to the PLC.

  3. After a moment, the readTag() function starts to throw errors, and the plc.established property changes to false.

  4. Wait a few moments, then restore the PLC's connectivity.

  5. After a moment, the plc.established property turns to true again, indicating that the library has reconnected to the PLC. However, any subsequent attempts to execute plc.readTag() fail with the following error: (note that the tag being read in this example is named "Int1" and is a Controller-scoped tag.

All subsequent readTag() functions fail until a new plc.connect(...) function is issued, at which point everything starts reading again.

Error: TIMEOUT occurred while writing Reading Tag: Int1.
at Controller._readTag ([snip]\node_modules\st-ethernet-ip\dist\controller\index.js:727:28)
at TaskEasy._runTask ([snip]\node_modules\task-easy\src\index.js:118:9)
at TaskEasy._next ([snip]\node_modules\task-easy\src\index.js:138:18)
at [snip]\node_modules\task-easy\src\index.js:56:22
at new Promise (<anonymous>)
at TaskEasy.schedule ([snip]\node_modules\task-easy\src\index.js:51:16)\
at Controller.readTag ([snip]\node_modules\st-ethernet-ip\dist\controller\index.js:591:34
at Driver_EthernetIP.read ([snip]\Driver_EthernetIP.class.js:150:19)
 โ€ฆ โ€ฆ

Supporting SEW VFD (MDX61B/MOVITRAC b drives)

I'm trying to get ethernet-ip working with SEW VFD's. These do NOT support the 0x6b class object used for tags. The drives support the Assembly (0x04) and Register (0x07) object classes. I have been able to connect and configure the drives using the library and the getAttributeSingle/setAttributeSingle methods. I did have to make one small change to the library to get it to work. Code is below for how I'm using the library.

What I'm wondering is:

  • Is there a better way to do this
  • I see that there is the IO object, and under the TCP directory looks like some code that may be useful as it uses the 0x04 Assembly object. But it's not exported.

I'm pretty green on Ethernet-IP. So any suggestions welcome.

Anyway here is how I'm using it to talk to the SEW drive. The small modification I had to make to the library was to add a Buffer parameter to the getAttributeSingle call. This is for getting drive parameter values, you need to send some data identifying which parameter you want to get.

import { ControllerManager, TagList, IO, Tag, Controller } from "st-ethernet-ip";
async function main() {
const PLC = new Controller();
// connect to the SEW VFD, do not do setup, while the VFD supports 
// Identity Class 0x01 (readControllerProps), it does not support
// Class 0x6b for tags (getControllerTagList)
PLC.connect("192.168.1.159", 0,false).then(async () => {
    // write process output data, there are 3 words, PO1/PO2/PO3
    // example configuration on the VFD:
    // PO1 = Control Word (direction of rotation, control command, param set, etc) (0x0005)
    // PO2 = Setpoint Speed (rpm of motor) (6000 rpm, encoded as 6000/0.2 = 30000 = 0x7530)
    // PO3 = Unassigned (set to 0x0000)
    const buf = Buffer.from("050030750000", 'hex');
    await PLC.setAttributeSingle(0x04,120, 3, buf );// class 0x04 Assembly Object, Instance 120 (decimal) output process data, attribute 3
    console.log('wrote PO data');
    // read the process input data, that is the actual values of the drive
    // example configuration
    // PI1 = Status Word
    // PI2 = Actual Speed
    // PI3 = Output Current
    const value = await PLC.getAttributeSingle(0x04, 130, 3);// class 0x04 Assembly Object, Instance 130 (decimal) input process data, attribute 3
    console.log('Got actual values from VFD: ' + value.toString('hex'));
    //SEW drive alays returns 10 words, we only care about the first 3

    //now read a parameter setting, this is done using the Register Object class 0.07
    //data needs to be passed in the getAttributeSingle call to identify which parameter
    //is to be read
    // read parameter 006 Motor Utilization, parameter index is 0x2083
    const paraBuf = Buffer.from("832000000000000000000000", 'hex');
    // paramBuf is in format of SEW paameter channel:
    // Index:       UINT : SEW parameter index (NOT the parameter number)
    // Data:        UDINT : Data(32 bit) 
    // SubIndex:    BYTE: Sew unit subindex (usually 0)
    // Reserved:    BYTE: 0
    // SubAddress1: BYTE: 0 if Parameter of Drive or com card, 1-63 for sbus
    // SubChannel1: BYTE: 0 if Parameter of Drive or com card, 2 sbus
    // SubAddress2: BYTE: 0
    // SubChannel2: BYTE: 0
    const paramValue = await PLC.getAttributeSingle(0x07, 1, 4, paraBuf); //class 0x07 Register, instance 1 to read (2 to set), attribute 4 param value 
    console.log('Got actual parameter value from VFD: ' + paramValue.toString('hex'));
    //we can set SEW paramters values as well, instance 2 must be used, the parameter and value is encoded same as for read
    //but the Data bytes are filled in with the new parameter value.
    // parameter 130 Speed Ramps1::Ramp t11 up CW, index 0x2116, value 6 seconds (6 seconds is transmitted as 6000)
    const newParaBuf = Buffer.from("1621701700000000000000000", 'hex');
    const newParamValue = await PLC.setAttributeSingle(0x07, 2, 4, newParaBuf); //class 0x07 Register, instance 1 to read (2 to set), attribute 4 param value 
    console.log('Set parameter succeeded');

}).catch((error) => {
    console.log(error);
  });
;

console.log('Hello world!');
}
main();

getAttributeSingle:

async getAttributeSingle(classID: number, instance: number, attribute: number, attData?: Buffer): Promise<Buffer> {
        const { GET_ATTRIBUTE_SINGLE } = CIP.MessageRouter.services;
        const { LOGICAL } = CIP.EPATH.segments;

        const identityPath = Buffer.concat([
            LOGICAL.build(LOGICAL.types.ClassID, classID), 
            LOGICAL.build(LOGICAL.types.InstanceID, instance), 
            LOGICAL.build(LOGICAL.types.AttributeID, attribute) 
        ]);

        const MR = CIP.MessageRouter.build(GET_ATTRIBUTE_SINGLE, identityPath, attData ? attData :  Buffer.from([]));

        super.write_cip(MR, super.established_conn);
...

Tags with Structures in Tag Groups vs Tags

I have a lot tags that are structures. If I read the tag with PLC.readTag(tag) the return is an array of objects with a key and value. When I add that same tag to a tag group the return value is a buffer. Is there any way to get the same return value as a tag read of a structure in a tag group?

Current Behavior

Expected Behavior

Possible Solution (Optional)

Context

Steps to Reproduce (for bugs only)

Your Environment

  • Package version (Use npm list - e.g. 1.0.6):
  • Node Version (Use node --version - e.g. 9.8.0):
  • Operating System and version:
  • Controller Type (eg 1756-L83E/B):
  • Controller Firmware (eg 30.11):

Expose handy classes and properties!

Hey, I'm giving a try to your lib, and I found that for some specific cases, the extController class, can be used at will without having to use the ControllerManager class.. this will be handy for example when we want to create just one controller and attach some custom information to it in an outer scope.

as you are exporting the ControllerManager by default, you are being forced to instatiate always the manager to get the extController which is pointless.

Also, I noted that the extController has a great support for auto-reconnection, but it will be nice to also expose the capability to desable the auto-reconnection, which right now we can not change or initialize at building time of the extController

It would be awesome if we can do it.

Add LGX String support

I realize that you are working on String support but I it looks like the README was last update 2 years ago and string support still isn't there. I work more with PLC's that utilize the LGX style of tags and I noticed that the LGX string is a STRUCT and has the same value as your STRUCT define (0x02a0). It's name, however, is "String" and its handle is 4060 when you grab the UDT information. Anyways, we rarely use any UDT's other than the string and so I would like to propose a temporary solution to support the String type which can then potentially be utilized for the future UDT support (I have some ideas there).

  1. Add "LGXSTR: 0x02a0" to your types in cip/data-types/index.js file (or replace STRUCT with LGXSTR for now)
  2. under tag/index.js edit 2 functions, "parseReadMessageResponseValueForAtomic" and "generateWriteMessageRequestForAtomic"
  • in both cases add LGXSTR to the types at the top of the function
  1. Add the following to the "parseReadMessageResponseValueForAtomic" switch statement:
case LGXSTR: // struct for string
                var len = data.readUInt32LE(4);
                var tmp = ""; 
                // build string here so controller_value doesn't fire too many
                // OnChange events for those subscribed to changes
                // or use a different converstion method
                for(var i = 0; i < len; i++)
                {
                    // LGX string header = 8 bytes 
                    tmp += String.fromCharCode(data[8+i]);
                }
                this.controller_value = tmp;
                break;
  1. Add the following to the "generateWriteMessageRequestForAtomic" switch statement:
case LGXSTR: // LGX string
                // override size with struct handle in header
                buf.writeUint16LE(0x0FCE,2);

                // string struct is a total of 90 by default
                var header = Buffer.alloc(6);
                header.writeInt16LE(1); // writing only one string
                header.writeInt32LE(tag.value.length,2); // length of string
                valBuf = Buffer.alloc(84); // standard string length
                valBuf.write(tag.value);

                buf = Buffer.concat([buf,header,valBuf]);
                break;

I have been testing this without any issues thus far. What I don't know is the impact it may have on reading other UDT's and so other checks will likely need to be added to avoid issues. Not sure where it's stored but if you had the handle from an initial read you could thrown an exception or exit with an error if the handle isn't 4060 (perhaps reading the UDT info to always get the correct handle to check may be necessary).
What are your thought on this solution?

why doesn't await PLC.getControllerTagList(tagList) work?

Current Behavior

returns:
node:436) UnhandledPromiseRejectionWarning: #
(Use node --trace-warnings ... to show where the warning was created)
(node:436) 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(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict
(see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:436) [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.

Expected Behavior

it should get tag list from PLC.

Possible Solution (Optional)

Context

const {Controller, Tag, TagList} = require('ethernet-ip');

const PLC = new Controller();
const tagList = new TagList();

PLC.connect('address ip', 0).then(async () => {
await PLC.getControllerTagList(tagList);
console.log(tagList);

});

Steps to Reproduce (for bugs only)

Your Environment

  • Package version (Use npm list - e.g. 1.0.6):
  • Node Version (Use node --version - e.g. 9.8.0):
  • Operating System and version: windows 7
  • Controller Type (eg 1756-L83E/B):
  • Controller Firmware (eg 30.11):

Unable to write to bit in integer tag or BOOL[] array

mainint is defined as an INT tag in Controller scope.
boolarray is defined as BOOL[32] in Controller scope.

Reading from "mainint.1" works with no error.
Reading from "boolarray.1" works with no error.

Writing to "mainint.1" throws a blank exception (no message or error).
Writing to "boolarray.1" throws a blank exception (no message or error)

UPDATE: if the exception is caught and output as console.error(JSON.stringify(err)) it's blank.
If not caught, the console outputs the following:

connected to PLC
Uncaught Error Error: Bit Indexes can only be used on SINT, INT, DINT, or BIT_STRING data types.
    at generateWriteMessageRequestForBitIndex (---/node_modules\st-ethernet-ip\dist\tag\index.js:594:23)
    at generateWriteMessageRequest (---node_modules\st-ethernet-ip\dist\tag\index.js:557:25)
    at _writeTag (---node_modules\st-ethernet-ip\dist\controller\index.js:805:24)
    at _runTask (---node_modules\task-easy\src\index.js:118:9)
    at _next (---node_modules\task-easy\src\index.js:138:18)
    at <anonymous> (---node_modules\task-easy\src\index.js:56:22)
    at schedule (---node_modules\task-easy\src\index.js:51:16)
    at writeTag (---node_modules\st-ethernet-ip\dist\controller\index.js:608:35)
    at run (---test\st-ethernet-ip.test.js:24:13)
    at <anonymous> (---test\st-ethernet-ip.test.js:11:2)
    at processTicksAndRejections (internal/process/task_queues:95:5)
Process exited with code 1

Here's the code:

const { Controller, Tag, TagList, EthernetIP  } = require('st-ethernet-ip');
const { SINT, INT, DINT, REAL, BOOL, USINT, UINT, UDINT, WORD, DWORD } = EthernetIP.CIP.DataTypes.Types;	
const plc = new Controller();

plc.connect('192.168.1.77', 0)
.then(() => { 
	console.log(`connected to PLC`)
	run();
})

async function run()
{
		const t = new Tag('boolarray.5', null, BOOL);
		t.value = true;
		await plc.writeTag(t);
}

Current Behavior

See above

Expected Behavior

Expect to write to a bit field of INT tag via "mainint.1"
Expect to write a bit in "boolarray"

Possible Solution (Optional)

Context

Unable to write bits of integer tags or elements of BOOL array tags.

Steps to Reproduce (for bugs only)

See above

Your Environment

  • Package version (Use npm list - e.g. 1.0.6): 2.7.2
  • Node Version (Use node --version - e.g. 9.8.0): 21.7.1
  • Operating System and version: Windows 10 x64 22H2
  • Controller Type (eg 1756-L83E/B): 1769-L35E
  • Controller Firmware (eg 30.11): 20.019

Error reading predefined ALARM tags

Can not read a predefined tag of type ALARM or ALARM_DIGITAL.

Current Behavior

The readTag() function returns the following error:

{ generalStatusCode: 15, extendedStatus: [] }

Expected Behavior

Read the tag without error.

Possible Solution (Optional)

Might have something to do with the extra SINT members that come along with structures that have BOOL members (one SINT for every 8 BOOLs). Just a thought because I am also experiencing incorrect data being written to DINT members, if the structure contains any BOOL members.

Context

Steps to Reproduce (for bugs only)

Run this code with a tag named 'ALM_1' defined as type ALARM.

const {Controller} = require('st-ethernet-ip')

const PLC = new Controller()

PLC.connect('10.0.0.250',0).then(async () => {

  console.log('Connected...')
  const udt = PLC.newTag('ALM_1')
  
  await PLC.readTag(udt)
  console.log('ALM_1:', udt.value)

}).catch(e => {
  console.log('Error: ', e)
})

Your Environment

  • Package version (Use npm list - e.g. 1.0.6): 2.5.0
  • Node Version (Use node --version - e.g. 9.8.0): 16.14.2
  • Operating System and version: OSX 10.15.7
  • Controller Type (eg 1756-L83E/B): 1769-L24ER-QB1B CompactLogix 5370
  • Controller Firmware (eg 30.11): 30.011

Unconnected send timeout value

Hi there, I'm the maintainer of the Node-RED node for Ethernet/IP. We currently use there the original library by Canaan, but it looks like it's not maintained anymore. I'm considering switching to this fork here.

Taking advantage that we'll be modifying the node, there's a small change that would be nice to have in order to support Omron PLCs that are currently not supported.

The default value of the unconnected send is currently 2000 ms here, but it needs to be at least 5024 ms for Omron PLCs to accept and process the request.

In my tests, changing it to 5024 doesn't affect the communication to the Rockwell PLCs I've tested, so we could either:

  • just change the default to 5024, or
  • make this value configurable as a constructor parameter of the Controller class

Either way, I can create a PR with the needed changes. What do you think about it?

Thanks!

STRING type returning Buffer data only

Maybe I'm jumping the gun, but I thought the support for STRING data types was added; however, upon trying to read them, I'm only able to get Buffer data. This also occurs when trying to read a string array of length 1.

value: <Buffer 08 00 00 00 30 31 2d 30 33 2d 32 33 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 38 more bytes>

Current Behavior

Returns buffer data instead of string text

Expected Behavior

Return string text

Your Environment

  • Package version (Use npm list - e.g. 1.0.6): [email protected]
  • Node Version (Use node --version - e.g. 9.8.0): 12.18
  • Operating System and version: Ubuntu 18.04
  • Controller Type (eg 1756-L83E/B): 5069-L306ER
  • Controller Firmware (eg 30.11): 30

I can't write to a tag, that does reads successfully.

Summary:

I want to write to some indexes inside an array in a program scope tag.
I'm able to read the tags, but when I attempt to write I get the following error:

Error: TIMEOUT occurred while writing Writing Tag: Program:[program].[tag-name]

Do you guys have a discord server?

Current Behavior:

When attempting to write to a tag array it's rejecting the promise on a TIMEOUT error.

Expected Behavior:

Write to manipulated tag array indexes.

Context

export const sendCommand = async (command: Command) => {
    try {
        const PLC = new Controller();
        await PLC.connect(command.ip, command.slot);

        const programName = command.commandTag.split(":")[1].split(".")[0];
        const tagName = command.commandTag.split(".")[1];
        const tagObj = new Tag(tagName, programName, Types.REAL, 0, 1, 1000);

        await PLC.readTag(tagObj);

        for (let i = 0; i < command.parameters.length; i++) {
            const parameter = command.parameters[i];
            tagObj.value[i] = parameter.value;
        }
        tagObj.value[command.offsetNum] = command.command;

        await PLC.writeTag(tagObj); // rejects this promise

        await PLC.disconnect();
    } catch (error) {
        console.log(error);
    }
};

Environment:

  • Package version (Use npm list - e.g. 1.0.6): 2.6.7
  • Node Version (Use node --version - e.g. 9.8.0): 18.16.1
  • Operating System and version: Ubuntu 23.04
  • Controller Type (eg 1756-L83E/B): 1756-L84E
  • Controller Firmware (eg 30.11): 32.013

PLC disconnection recovery after reconnect

Current Behavior

Great work guys, I can see this wonderful package.
I am trying to use this to build a application pulling data from PLCs and dump all the data on the information screen, I don't want the information go for problem as I setup my client screen auto refresh mode (every x seconds). once I unplug ethernet cable after a certain period I got time out time out problem, I use try catch to catch the error and replace with initialization tags information but I seem can not bypass the connection even though I saw the time out error, so basically my screen change to white question screen unless I plug the cable back. when I have SQL query running in the same situation, I could catch error and dump screen with initialization data of the tags from SQL, but this technology used for MS SQL seems not working for this package. I wonder if you have any idea can lighting up?

error message is:
(node:7932) UnhandledPromiseRejectionWarning: Error: TIMEOUT occurred while attempting to establish TCP connection with Controller.
at Controller.connect (C:\Users\Public\Documents\marquee_hdb\node_modules\st-ethernet-ip\src\enip\index.js:163:28)
at processTicksAndRejections (internal/process/task_queues.js:93:5)
at async Controller.connect (C:\Users\Public\Documents\marquee_hdb\node_modules\st-ethernet-ip\src\controller\index.js:191:24)

Expected Behavior

I expect when I lost connection, the PLC connection error can be caught by try catch block and replace the tags reading with their initialization value.

Possible Solution (Optional)

Context

Steps to Reproduce (for bugs only)

Your Environment

  • Package version (Use npm list - e.g. 1.0.6): "st-ethernet-ip": "^2.3.2"
  • Node Version (Use node --version - e.g. 9.8.0): v14.16.1
  • Operating System and version: Windows server 2019 std
  • Controller Type (eg 1756-L83E/B): L73, L61
  • Controller Firmware (eg 30.11): Version 20, Version 16

ControllerManager 'TagChanged' event anomaly

When monitoring a UDT with BOOL members, the first member's value unexpectedly changes if there is a subsequent BOOL member in the UDT.

Current Behavior

Value of the first member of the UDT unexpectedly changes. Could create unpredictable behavior of the control system.

Expected Behavior

Monitor UDT's with BOOL members without effecting the first member.

Possible Solution (Optional)

Context

This use case only needs to read values, never write.

Steps to Reproduce (for bugs only)

  1. Create a UDT (UDT_1) in the PLC with two members. The first as a DINT, the second a BOOL.
  2. Run the code below and monitor the value of the DINT member (RSLogix).
  3. Change the value of the DINT and it will change back to something else (depending on the value of the BOOL).
  4. Change the value of the BOOL and the DINT value will unexpectedly change.
const {ControllerManager} = require('st-ethernet-ip')

const cm = new ControllerManager();

//addController(ipAddress, slot = 0, rpi = 100, connected = true, retrySP = 3000, opts = {})
const cont = cm.addController('10.0.0.250');

cont.connect();

//addTag(tagname, program = null, arrayDims = 0, arraySize = 0x01)
cont.addTag('UDT_1')

cont.on('TagChanged', (tag, prevValue) => {
  console.log(tag.name, ' changed from ', prevValue, ' => ', tag.value)
})

cont.on('error', (e) => {
  console.log(e)
})

Your Environment

  • Package version (Use npm list - e.g. 1.0.6): 2.5.0
  • Node Version (Use node --version - e.g. 9.8.0): 16.14.2
  • Operating System and version: OSX 10.15.7
  • Controller Type (eg 1756-L83E/B): 1769-L24ER-QB1B CompactLogix 5370
  • Controller Firmware (eg 30.11): 30.011

Ethernet/IP Scanner Function

Hello creator and good work with this repository!!

I have a few questions and I am unsure where to bring them up other than here, so excuse me if this is the wrong forum.

I was thrilled to see that this repository had I/O Scanner as I am currently trying to establish communication to a Fanuc Robot Controller R-30iB Mate. The robot controller works as Ethernet/IP Adapter and writes its inputs to Instance number e.g 101 and outputs to Instance number e.g 151.

The way I would like to achieve communication is through explicit message (tcp) to be able to read both I/Os and register acyclically, cyclic is not important so implicit message (udp) might be good to have for future case.

I am currently looking to try to implement this to Node-RED where configuration can simply be made what instances are to be read and written by specifying:

  • Class
  • Instance
  • Attribute
  • Service

Reading the instance numbers e.g 101 and 151 is priority and will get me on the way for what I am currently working on, but having the flexibility to specifiy what to read and write will give me almost complete data exchange with any Ethernet/IP adapter.

Now to the questions,

  • Do you think this is possible with the current state of this repository? I noticed in the example code that I/O Scanner was Alpha and not for production.
  • Depending on answer above, is there a timeframe when this will be complete? Is it being further worked on/developed?

Attached is a .pdf file for the EIP for the Fanuc Robot Controller, especially interesting is page 92-142, page 139 is good for what I want to achieve foremost.

R-30iB_EIP_operator_manual_[MAROC77EN01101E_Rev.G].pdf

What does "status" means in properties object?

I need to know, what exactly does "status" means in propetries object. Example:

{
  name: '5069-L340ERM/A',
  serial_number: 1620037161,
  slot: 0,
  time: null,
  path: <Buffer 01 00>,
  version: '34.11',
  status: 8304,
  faulted: false,
  minorRecoverableFault: false,
  minorUnrecoverableFault: false,
  majorRecoverableFault: false,
  majorUnrecoverableFault: false,
  io_faulted: false
}

I need it to know if the PLC is in run mode or not. Although I trace which numbers belong to which modes, but I would like to know the full meaning. I know it's some kind of bit word, but I couldn't find anywhere, what the bits means. Is there any documentation for this? Can anyone advise me, please? Thank you.

Improve Unknown tags error handling.

One of the things I've noticed is that, whenever a tag is unkown this error is thrown:

{ generalStatusCode: 4, extendedStatus: [ 0 ] }

This is not really usefull, because instead of saying which variable is failing... it throws this message but all the other variables can not be read, and we get a bunch of nulls.

it should be nice to have the conflicted variable with some specific status or null and the other ones performing the readings. if this is not possible, at least improve the error so we can know what is happening.

This can be reproduces adding an unexisting tag.

Also, not having this can lead us to a memory leak eventually due to multiple listeners set and undestroyed in the underlayer of the emitter like so:

(node:16260) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 Multiple Service Packet listeners added to [Controller]. Use emitter.setMaxListeners() to increase limit

Timestamp not updated on unknown tag

Current Behavior

When an unknown tag is encountered the timestamp is not updated.

Expected Behavior

Timestamp should reflect time of emit.

Solution

Will submit pull request momentarily.

Unable to read tags outside of PLC.connect callback function

Current Behavior

PLC.connect("192.168.2.235", 1).then(async (err) => { PLC.readTag(tag); });
If the code to read a tag is within that callback, it works fine; however, if it lies within another function, say on an interval, it times out. Although, I can read PLC.properties just fine in the external functions.

Error: TIMEOUT occurred while writing Reading Tag: Analog_Inputs[1]

Expected Behavior

Once the PLC is connected, I should be able to summon PLC.readTag from elsewhere. (This works on the original repo)

Context

Set up an interval where a tag's value is read and displayed in the console.

Your Environment

  • Package version (Use npm list - e.g. 1.0.6): 2.4.4
  • Node Version (Use node --version - e.g. 9.8.0): 12.18.3
  • Operating System and version: Ubuntu 18.04
  • Controller Type (eg 1756-L83E/B): Tested with both CompactLogix L18 and ControlLogix L73
  • Controller Firmware (eg 30.11): 20.12 & 31.11

Micro Queue is already full

Current Behavior

At random times, the script will stop reading data from a 1756-L81E ControlLogix. The script also reads from a 1769-L32E and that data continues to read normally. This error occurred before the introduction of the controller manager, too.

From my PM2 log:
0|plc | 2023-08-29 07:26:16: Reading Error - F8[41] - Micro Queue is already full at size of 100!!!
0|plc | 2023-08-29 07:26:16: Reading Error - Analog_Inputs[6] - Micro Queue is already full at size of 100!!!
0|plc | 2023-08-29 07:26:17: Reading Error - F8[41] - Micro Queue is already full at size of 100!!!
0|plc | 2023-08-29 07:26:18: Reading Error - F8[41] - Micro Queue is already full at size of 100!!!
0|plc | 2023-08-29 07:26:18: Reading Error - Discrete_Outputs[35].Out - Micro Queue is already full at size of 100!!!
0|plc | 2023-08-29 07:26:19: Reading Error - F8[41] - Micro Queue is already full at size of 100!!!
0|plc | 2023-08-29 07:26:20: Reading Error - F8[41] - Micro Queue is already full at size of 100!!!
0|plc | 2023-08-29 07:26:21: Reading Error - F8[41] - TIMEOUT occurred while writing Reading Tag Group.
0|plc | 2023-08-29 07:26:22: Reading Error - F8[41] - Micro Queue is already full at size of 100!!!
0|plc | 2023-08-29 07:26:23: Reading Error - F8[41] - Micro Queue is already full at size of 100!!!
0|plc | 2023-08-29 07:26:23: Reading Error - Discrete_Outputs[35].Out - Micro Queue is already full at size of 100!!!
0|plc | 2023-08-29 07:26:24: Reading Error - F8[41] - Micro Queue is already full at size of 100!!!
0|plc | 2023-08-29 07:26:25: Reading Error - F8[41] - Micro Queue is already full at size of 100!!!
0|plc | 2023-08-29 07:26:26: Reading Error - F8[41] - Micro Queue is already full at size of 100!!!
0|plc | 2023-08-29 07:26:26: Reading Error - Analog_Inputs[6] - Micro Queue is already full at size of 100!!!

Expected Behavior

Should continue reading PLC.

Possible Solution (Optional)

Context

Steps to Reproduce (for bugs only)

Unable to reproduce. Will work fine for days or weeks before throwing these errors.

Your Environment

  • Package version (Use npm list - e.g. 1.0.6): 2.6.1
  • Node Version (Use node --version - e.g. 9.8.0): 12.21
  • Operating System and version: 4.4.180+
  • Controller Type (eg 1756-L83E/B): 1756-L81E
  • Controller Firmware (eg 30.11): 30.11

readTag() and writeTag() throw exceptions reading/writing BOOL[] array tags

Current Behavior

Controller: 1769-L35E, firmware 20.19
Controller-scoped boolean array tag: BoolTag, type BOOL[32]

Attempting to read BoolTag[2] throws exception: {generalStatusCode: 5, extendedStatus: Array(0)}
Attempting to write BoolTag[2] throws exception: {"generalStatusCode":255,"extendedStatus":[8455]}
Attempting to read BoolTag[0] returns an array of all array elements (32 boolean values).

Code:

const tag1 = new Tag("BoolTag[0], null, BOOL);
const tag2 = new Tag("BoolTag[2], null, BOOL);

plc.readTag(tag1)
.then(() => {
    console.log(`Tag value: ${tag1.value} of type ${typeof tag1.value}`);
   // Output: Tag value: false,true,false,true,false,true,false,true,false,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false of type object
})
.catch((err) => {
    console.error(err);
});

plc.readTag(tag2)
.then(() => {
    console.log(`Tag value: ${tag2.value} of type ${typeof tag2.value}`);
})
.catch((err) => {
    console.error(err);
   // Output: {generalStatusCode: 5, extendedStatus: Array(0)}
});

Reading INT array tags works with no issues (i.e. "IntTag[2]" returns the tag integer value)

Expected Behavior

Expect that any attempt to read a BOOL tag array element returns a single BOOL value, not an array of values, and not throws an exception.

Possible Solution (Optional)

n/a

Context

Trying to read a few individual BOOL array tags for status values, without reading the entire array, which could be many hundreds of elements.

Steps to Reproduce (for bugs only)

See code above.

Your Environment

  • Package version (Use npm list - e.g. 1.0.6): [email protected]
  • Node Version (Use node --version - e.g. 9.8.0): v21.7.1
  • Operating System and version: Windows 10 x64 22H2
  • Controller Type (eg 1756-L83E/B): 1769-L35E
  • Controller Firmware (eg 30.11): 20.19

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.