Coder Social home page Coder Social logo

nodes7's Introduction

nodeS7

NodeS7 is a library that allows communication to S7-300/400/1200/1500 PLCs using the Siemens S7 Ethernet protocol RFC1006.

This software is not affiliated with Siemens in any way, nor am I. S7-300, S7-400, S7-1200 and S7-1500 are trademarks of Siemens AG.

WARNING

Fully test everything you do. In situations where writing to a random area of memory within the PLC could cost you money, back up your data and test this really well. If this could injure someone or worse, consider other software.

Installation

Using npm:

  • npm install nodes7

Using yarn:

  • yarn add nodes7

Optimization

  • It is optimized in three ways - It sorts a large number of items being requested from the PLC and decides what overall data areas to request, then it groups multiple small requests together in a single packet or number of packets up to the maximum length the PLC supports, then it sends multiple packets at once, for maximum speed. So a request for 100 different bits, all close (but not necessarily completely contiguous) will be grouped in one single request to the PLC, with no additional direction from the user.

  • NodeS7 manages reconnects for you. So if the connection is lost because the PLC is powered down or disconnected, you can continue to request data with no other action necessary. "Bad" values are returned, and eventually the connection will be automatically restored.

  • NodeS7 is written entirely in Javascript, so no compiler installation is necessary on Windows, and deployment on other platforms (ARM, etc) should be no problem.

PLC Support

  • S7-1200 and S7-1500 CPU access requires access using "Slot 1" and you must disable optimized block access (in TIA portal) for the blocks you are using. In addition, you must "Enable GET/PUT Access" in the 1200/1500 controller in TIA Portal. Doing so opens up the controller for other access by other applications as well, so be aware of the security implications of doing this.

  • This has been tested on direct connections to newer PROFINET CPUs and Helmholz NetLINK PRO COMPACT and IBH units. (Note with these gateways you often have to specify the MPI address as the slot number) It is reported to work with other CPU/CP combinations as well, although not all S7-200 datatypes are supported. S7 routing is not supported.

  • Logo 0BA8 PLCs are supported although you should set your local and remote TSAP to match your project, and your addresses have to be specified differently. DB1,INT0 should get VM0. DB1,INT1118 should get AM1.

VFD Support

  • SINAMICS S120 and G120 FW 4.7 and up work as well, as these drives support direct connection USING SLOT 0 (instead of other examples that use 1 or 2) and some modified parameter addressing. This technique can work with these drives with other software as well and is documented on the Siemens website. Basically, to address parameter number 24, output frequency for example, is defined in the documentation as a real number, so DB24,REAL0 would return the output frequency. If this parameter were an array, DB24,REAL1 would return the next in sequence even though a Siemens programmer would be tempted to use REAL4 which is not correct in this case. For this reason, normal S7 optimization must be disabled. After you declare conn = new nodes7; (or similar) then add conn.doNotOptimize = true; to ensure this isn't done, and don't try to request these items using array notation as this implies optimization, request REAL0 then REAL1 etc. doNotOptimize is now also supported as a connection parameter.

Credit to the S7 Wireshark dissector plugin for help understanding why things were not working. (http://sourceforge.net/projects/s7commwireshark/)

Examples

var nodes7 = require('nodes7'); // This is the package name, if the repository is cloned you may need to require 'nodeS7' with uppercase S
var conn = new nodes7;
var doneReading = false;
var doneWriting = false;

var variables = {
      TEST1: 'MR4',          // Memory real at MD4
      TEST2: 'M32.2',        // Bit at M32.2
      TEST3: 'M20.0',        // Bit at M20.0
      TEST4: 'DB1,REAL0.20', // Array of 20 values in DB1
      TEST5: 'DB1,REAL4',    // Single real value
      TEST6: 'DB1,REAL8',    // Another single real value
      TEST7: 'DB1,INT12.2',  // Two integer value array
      TEST8: 'DB1,LREAL4',   // Single 8-byte real value
      TEST9: 'DB1,X14.0',    // Single bit in a data block
      TEST10: 'DB1,X14.0.8'  // Array of 8 bits in a data block
};

conn.initiateConnection({ port: 102, host: '192.168.0.2', rack: 0, slot: 1, debug: false }, connected); // slot 2 for 300/400, slot 1 for 1200/1500, change debug to true to get more info
// conn.initiateConnection({port: 102, host: '192.168.0.2', localTSAP: 0x0100, remoteTSAP: 0x0200, timeout: 8000, doNotOptimize: true}, connected);
// local and remote TSAP can also be directly specified instead. The timeout option specifies the TCP timeout.

function connected(err) {
  if (typeof(err) !== "undefined") {
    // We have an error. Maybe the PLC is not reachable.
    console.log(err);
    process.exit();
  }
  conn.setTranslationCB(function(tag) { return variables[tag]; }); // This sets the "translation" to allow us to work with object names
  conn.addItems(['TEST1', 'TEST4']);
  conn.addItems('TEST6');
  // conn.removeItems(['TEST2', 'TEST3']); // We could do this.
  // conn.writeItems(['TEST5', 'TEST6'], [ 867.5309, 9 ], valuesWritten); // You can write an array of items as well.
  // conn.writeItems('TEST7', [666, 777], valuesWritten); // You can write a single array item too.
  conn.writeItems('TEST3', true, valuesWritten); // This writes a single boolean item (one bit) to true
  conn.readAllItems(valuesReady);
}

function valuesReady(anythingBad, values) {
  if (anythingBad) { console.log("SOMETHING WENT WRONG READING VALUES!!!!"); }
  console.log(values);
  doneReading = true;
  if (doneWriting) { process.exit(); }
}

function valuesWritten(anythingBad) {
  if (anythingBad) { console.log("SOMETHING WENT WRONG WRITING VALUES!!!!"); }
  console.log("Done writing.");
  doneWriting = true;
  if (doneReading) { process.exit(); }
}

API

nodes7.initiateConnection(options, callback)

Description

Connects to a PLC.

Arguments

Options

Property type default
rack number 0
slot number 2
port number 102
host string 192.168.8.106
timeout number 5000
localTSAP hex undefined
remoteTSAP hex undefined

callback(err)

err
err is either an error object, or undefined on successful connection.

nodes7.dropConnection(callback)

Description

Disconnects from a PLC. This simply terminates the TCP connection.

Arguments

callback()

The callback is called upon completion of the close.

nodes7.setTranslationCB(translator)

Description

Sets a callback for name - address translation.

This is optional - you can choose to use "addItem" etc with absolute addresses.

If you use it, translator should be a function that takes a string as an argument, and returns a string in the following format: <data block number.><memory area><data type><byte offset><.array length>

Examples:

  • MR30 - MD30 as REAL
  • DB10,LR32 - LREAL at byte offset 32 in DB10, for 1200/1500 only
  • DB10,INT6 - DB10.DBW6 as INT
  • DB10,I6 -same as above
  • DB10,INT6.2 - DB10.DBW6 and DB10.DBW8 in an array with length 2
  • DB10,X14.0 - DB10.DBX14.0 as BOOL
  • DB10,X14.0.8 - DB10.DBB14 as an array of 8 BOOL
  • PIW30 - PIW30 as INT
  • DB10,S20.30 - String at offset 20 with length of 30 (actual array length 32 due to format of String type, length byte will be read/written)
  • DB10,S20.30.3 - Array of 3 strings at offset 20, each with length of 30 (actual array length 32 due to format of String type, length byte will be read/written)
  • DB10,C22.30 - Character array at offset 22 with length of 30 (best to not use this with strings as length byte is ignored)
  • DB10,DT0 - Date and time
  • DB10,DTZ0 - Date and time in UTC
  • DB10,DTL0 - DTL in newer PLCs
  • DB10,DTLZ0 - DTL in newer PLCs in UTC

The DT type is the well-known DATE_AND_TIME type of S7-300/400 PLCs, a 8-byte-wide field with BCD-encoded parts

The DTZ type is the same as the DT, but it expects that the timestamp is in UTC in the PLC (usually NOT the case)

The DTL type is the one seen on newer S7-1200/1500 PLCs, is 12-byte long and encodes the timestamp differently than the older DATE_AND_TIME

The DTLZ type is also the same as the DTL, but expecting the timestamp in UTC in the PLC

In the example above, an object is declared and the translator references that object. It could just as reference a file or database. In any case, it allows cleaner Javascript code to be written that refers to a name instead of an absolute address.

nodes7.addItems(items)

Description

Adds items to the internal read polling list.

Arguments

items can be a string or an array of strings.

If items includes the value _COMMERR it will return current communication status.

nodes7.removeItems(items)

Description

Removes items to the internal read polling list.

Arguments

items can be a string or an array of strings.

If items is not defined then all items are removed.

nodes7.writeItems(items, values, callback)

Description

Writes items to the PLC using the corresponding values and calls callback when done.

You should monitor the return value - if it is non-zero, the write will not be processed as there is already one it progress, and the callback will not be called.

Arguments

items can be a string or an array of strings.

If items is a single string, values should then be a single item.

If items is an array of strings, values must also be an array of values.

callback(err)

err
a boolean indicating if ANY of the items have "bad quality".

nodes7.readAllItems(callback)

Description

Reads the internal polling list and calls callback when done.

Arguments

callback(err, values)

err
a boolean indicating if ANY of the items have "bad quality".
values
an object containing the values being read as keys and their value (from the PLC) as the value.

nodes7's People

Contributors

adopozo avatar babinc avatar bsdelf avatar gfcittolin avatar luisbardalez avatar pablitovicente avatar pilhokim avatar plcpeople avatar vaaski 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  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  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  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  avatar  avatar  avatar  avatar  avatar  avatar

nodes7's Issues

Issue when receiving multiple packets at once

We're having an issue, where nodeS7 is treating a packet that is apparently correct as invalid.

...
[997,136871469 172.25.24.210 S2] SendReadPacket called
[997,137073486 172.25.24.210 S2] Sending Read Packet
[997,137322621 172.25.24.210 S2] Sending Read Packet
[997,138683123] INVALID READ RESPONSE - DISCONNECTING
[997,138820445] TPKT Length From Header is 231 and RCV buffer length is 468 and COTP length is 2 and data[6] is 128
[997,138856085] <Buffer 03 00 00 e7 02 f0 80 32 03 00 00 00 02 00 02 00 d2 00 00 04 0b ff 04 00 70 00 00 00 00 00 09 00 00 00 00 00 00 00 00 ff 04 00 70 00 00 00 00 00 00 00 ... >
[997,139296666] ConnectionReset is happening

I've analyzed it a bit and, for the case we have here, it looks like that onResponse is being called with two packages in the buffer (maybe the system was a bit slow at the moment) - this explains the TPKT length being 231 and the buffer length being 468 for the example above.

The code even treat this special case here, but it looks like the code isn't reaching this anymore because of the fastACK check being mate by checkRFCData:

   //...
   }else if((LastDataUnit >> 7) == 1 && TPKT_Length === data.length){
   //...
   }else{
      ret='error';
   }

this causes ret being assigned 'error'instead of the buffer. Maybe the if-else comparison should be changed to:

   //...
   }else if((LastDataUnit >> 7) == 1 && TPKT_Length <= data.length){
   //...
   }else{
      ret='error';
   }

thus allowing the check previous mentioned check to be executed and succeed.

I have no experience with this fastACK functionality, therefore I don't know if this could break something. But if you agree on that I can create a PR for the modification above

'Bad 255' Data due to Race Conditions

Hello, everyone,
I've discovered a bug that shouldn't exist.

The variable requestMaxParallel and maxparallel are used to define the number of parallel jobs in the network. These connection parameters are negotiated with the PLC in the function onPDUReply. That's working as far as I can tell. (see)

This error means that I have set the values from 8 to 1 and still two orders are sent.

The error occurred with a WinAC. Because of "Fast Acknowledge" I have set the values from 8 to 1.

On the following picture you can see a Wireshark section:

error

Packets 236,237 and 238 show a successful data exchange (including Fast Acknoledge).
Packet 240 shows a transmission request. Packet 242 another one, although maxparallel is set to 1 (!).

The error behavior is that with the received stream data (usually 460 bytes) are not complete.
e. g.:
[2482,147791652 172.20.15.70 S2] Address DB11134, BYTE0.6456 has value
0,..., 0,0,0,0,0,8..., 3,3,32, and quality BAD 255,..., BAD 255, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK, OK

Connection cleanup without destroying socket

We're having a pretty hard to solve issue on st-one-io/node-red-contrib-s7#3. Some users of this Node-RED node are reporting that an uncaught exception related to the TCP connection is bringing the whole process down. I've already spent quite some hours trying to simulate it and I could not reproduce it. However, analyzing nodes7's code, I could find one special case where such a thing could happen.

In my previous experiences dealing with net.Socket, I found out it's only safe to remove all listeners from a socket after calling its destroy() method or after the close event, making sure that no more i/o operations will happen on it, according to the docs.

On nodes7, however, all listeners are removed by calling connectionCleanup(), but destroy() is not called there. destroy() is only called on the timeout of dropConnection(), but connectionCleanup() is called from other places too, specially by connectNow(). Therefore, in some special cases, like packet timeouts, connectNow() may be called (and by consequence connectionCleanup()) without the previous connection being completely closed. This could lead to these strange exceptions being thrown.

Finally, I would like to suggest a modification: move the destroy() call to the connectionCleanup(), so we'd make sure we wouldn't left anything open before removing the listeners for errors. I hope this fixes or at least amends the problems there :)

Thanks!

TypeScript Port

Hi, any intention to port this to TypeScript?
We could benefit from Async/Await and other ES2015 features while mantaining compatibility with ES3 and the actual API of nodeS7.

Also, if interested I can work on this.

Need tests

We need to add tests in order not to break anything while adding new features/fixing bugs.

ET-200s Communication Problem

Hi,

When I try to communicate with my "Et200s" PLC it is connecting with desire IP & Port Correctly, but then after it is Disconnected showing " Error - TCP Connected , ISO didn't

connectionissue

Nodes7- Siemens S7 200 Smart. Variable word memory Variable Byte VB not supporting

Hello,
I have tested this node with node-red with my raspberrypi and Siemens S7200 smart PLC
It supports variable like. Input (I0.0) , Output (Q0.0), Memory Variables MW, MB. and working well.

But not able to read & write Variable Memory VB, VW , Vbit, and timer e.g T100 , counters.

Please help to how to get control this variable with nodeS7.

Cannot Read DB155.DBD332,FLOAT type on S7 1200

Hi plcpeople
I tried read data from PLC S7 1200. But I can't read data with data type float from PLC.
DB155.DBD332,FLOAT0
DB155.DBD332,FLOAT0.0
with no success.

could you tell me what the type of float is?

ECONNRESET error with S7-400H

Is there any experience with S7-400H (it is the high availability version with two IP-Addresses)?
I get the "Error connecting to PLC: Error: read ECONNRESET" error.

I'm using it via node-red 0.17.5, node-red-contrib-s7 1.4.0 and nodes7 0.2.5.

Bug: Error on log output when slicing response buffer

When we receive multiple response packets from the PLC very fast, we must split them accordingly. Even though the function seems to be working correctly, the log output is producing a weird "NaN.":

...
[2633,113671889 172.168.31.60 S1] SendReadPacket called
[2633,212312295 172.168.31.60 S1] Sending Read Packet
[2633,218683916] NaN.  
[2633,239537615] We assume this is because two packets were sent at nearly the same time by the PLC.
[2633,241705139] We are slicing the buffer and scheduling the second half for further processing next loop.
[2633,244438727 172.168.31.60 S1] Received 220 bytes of S7-data from PLC.  Sequence number is 37
...

It looks like there's a simple fix for this, just a formatting issue. It's a small issue, but it's kind of annoying when analyzing bigger problems. I'll submit a PR for this.

TypeError: String.toCharCode is not a function

Found a bug in line 1929:
//theItem.writeBuffer.writeUInt8(String.toCharCode(theItem.writeValue), thePointer);//buggy
theItem.writeBuffer.writeUInt8(theItem.writeValue.charCodeAt(theItem.writeValue), thePointer);

Scenario to reproduce: Write char
conn.writeItems('DB111,CHAR4', 'f', valuesWritten);

Can anyone confirm?

Node-RED crashes while reading data

Hello, i'm working on a student project and got a 'big' issue :

i have a local s7-1500 i'm working with and a gateway with node-red container installed inside docker.

reading out the data with S7in Node is no problem, but when i'm using the example code (from the readme) and put in my adress (just an array of 8 integers for testing) , node-red crashes after ~120s.
First it works fine, i'm receiving the data as expected, but after this time i'm loosing connection to node-red.
The problem is reconstructable.. any ideas?
best regards

Impossible to drop connection with wrong connection parameters

I've found an odd condition, where nodeS7 keeps trying to reconnect forever, and there's no way to stop it.

I've simulated the following with an S7-1200:
If you create a connection with a wrong parameter (e.g. wrong slot), we'll open the TCP socket, onTCPConnect() ist called, but then the connection is rejected after the ISO-on-TCP connection because of the wrong parameter. error and close events are emitted, and they both correctly triggers the cleanup process by calling connectionReset() and resetNow().
The main problem happens with the connectTimeout from onTCPConnect(): There, the packetTimeout() gets called with he "connect" parameter, and this calls connectNow() again after some time. But as the parameters are wrong, the same error will happen again, and this will keep happening forever. There's no way to stop it but to kill the process.

I see two possible solutions here:

  • Make dropConnection() to stop the loop: dropConnection() is the way we currently have to close the communication, so we could either:
    • set a flag on dropConnection() signalizing we're dead, so 'connectNow()' would just skip it, or
    • make dropConnection() clean the timer from packetTimeout(), preventing the connection reset to happen again
  • Don't try to reconnect on these connection errors: This is actually the case when we have an invalid IP address, for example. On both cases (wrong IP and wrong slot), the connection callback is called, but on the first case it stops, and on the second one it keeps trying (even after the callback is called). So here, we could:
    • stop the connectTimeout timer from onTCPConnect() if we get an error event (on the connectError()).

The second solution seems more correct in my point of view, as it should stop doing anything if the connection callback is called with an error.

What do you think about it? I can create then a PR with the fix for this using the solution chosen.

P.S.: This seems to be the cause of the issues st-one-io/node-red-contrib-s7#26 and st-one-io/node-red-contrib-s7#29

dropConnection on error

I have a problem to drop a connection instance when a previous initiateConnection() has returned an error.
Use Case:

  • I open multiple connections successfully until no more connections are accepted, which results in a connection error (ECONNRESET).
  • From now on that last connection instance endlessly tries to connect, I did not find a way to just stop it.
    A call to dropConnection() has no effect (also tried isoclient.destroy())
    Intresting here is: When I drop a successfully initiated connection then the error connection will also end ...
    I just couldn't find the 'outer' timer that constantly repeats the connection...

That behaviour only applies to ECONNRESET, not ETIMEDOUT

Any thoughts?

Quickly tested out this module and received error making ISO-on-TCP Connection

I just ran this test against an local s7 we have. The only thing I changed from the example code was the IP. I'm not familiar with ISO-on-TCP. Am I missing something on the configuration?

[97849,313122985] Initiate Called - Connecting to PLC with address and parameters:
[97849,313985846] { port: 102, host: '10.2.202.145', rack: 0, slot: 1 }
[97849,315746540] Connection cleanup is happening
[97849,329727559 10.2.202.145 S1] Attempting to connect to host...
[97849,334747742 10.2.202.145 S1] TCP Connection Established to 10.2.202.145 on port 102
[97849,334815782 10.2.202.145 S1] Will attempt ISO-on-TCP connection
[97849,341580313 10.2.202.145 S1] ISO-on-TCP connection DISCONNECTED.
Error - TCP connected, ISO didn't

wrong require in exemple

Hy,

I had to change :

require('nodeS7');

into

require('nodes7');

to make the test run.

Thanks, great jobs, it runs almost out of the box with S7-1200.

connect error ECONNRESET

Hello, after being about 10 minutes reading, it gives this error and I can not control it to continue the execution. (S7-1500 )

Does anyone know why this might happen?

Thank you.

[6802,958350399] Connection cleanup is happening
[6802,958702800 192.168.0.2 S1] Attempting to connect to host...
[6802,959635499 192.168.0.2 S1] TCP Connection Established to 192.168.0.2 on port 102
[6802,959848699 192.168.0.2 S1] Will attempt ISO-on-TCP connection
[6802,960114000 192.168.0.2 S1] Using rack [0] and slot [1]
[6802,961254600 192.168.0.2 S1] ISO-on-TCP Connection Confirm Packet Received
[6802,962537699] We Caught a read/write error ECONNRESET - will DISCONNECT and attempt to reconnect.
[6802,962793700] ConnectionReset is happening
[6802,963064500] ConnectionReset is happening
[6804,461757300] TIMED OUT waiting for PDU reply packet from PLC - Disconnecting
[6804,462975099 192.168.0.2 S1] Wait for 2 seconds then try again.
[6804,463273599] ConnectionReset is happening
[6804,463524400 192.168.0.2 S1] Scheduling a reconnect from packetTimeout, connect type
[6804,464642200] ResetNOW is happening
[6804,464870400] Clearing an earlier scheduled reset
[6806,463175399 192.168.0.2 S1] The scheduled reconnect from packetTimeout, PDU type, is happening now
[6806,464447400] Connection cleanup is happening
[6806,464894500 192.168.0.2 S1] Attempting to connect to host...
[6806,466437600 192.168.0.2 S1] TCP Connection Established to 192.168.0.2 on port 102
[6806,466659799 192.168.0.2 S1] Will attempt ISO-on-TCP connection
[6806,466880999 192.168.0.2 S1] Using rack [0] and slot [1]
[6806,468413500 192.168.0.2 S1] We Caught a connect error ECONNRESET
{ Error: read ECONNRESET
at _errnoException (util.js:992:11)
at TCP.onread (net.js:618:25) code: 'ECONNRESET', errno: 'ECONNRESET', syscall: 'read' }

Little problem using multiple TranslationCB's and reads

Hi,

I using context sensible translationCB's.

Now if I add items and don't read, then change context, remove old and add the new items and change translationCB, I get an error on the next read. Because the old items in the addRemoveArray are not covered by the latest translationCB.

I solved this by removing all unnessesary addItems but I am sure the is a better solution.

track connection ending flag

Hellooo,
Question: How can i track if the tcp Connection is ended in case of closing it?

I want to reconnect my connection after the RST packet of the plc arrived. At the moment the reconnection is 1,5 sec before the RST packet. (see Wireshark trace.) because of the Timeout function in NodeS7.prototype.connectionReset = function() { ... };

pic

How can i track the reset? Maybe with self.resetPending?

Thanks

Cannot Read DB1,BOOL type on S7 1200

Hi, while trying to read BOOL located in a DB, I cannot access to it,
I tried
DB1,BOOL0
DB1,BOOL0.0
with no success.
Is this a lack from your implementation, or shall I investigate on PLC/firmware/TIAportal side ?

Error on writing more then 32 byte of data

Hello,

I've got the following log:

[18193,176543379] Initiate Called - Connecting to PLC with address and parameters:
[18193,182467207] { host: '192.168.36.94', port: 102, slot: 1, rack: 0 }
[18193,209406185] Connection cleanup is happening
[18193,216527877 192.168.36.94 S1] Attempting to connect to host...
[18193,224857695 192.168.36.94 S1] TCP Connection Established to 192.168.36.94 on port 102
[18193,227583800 192.168.36.94 S1] Will attempt ISO-on-TCP connection
[18193,235965423 192.168.36.94 S1] ISO-on-TCP Connection Confirm Packet Received
[18193,242886738 192.168.36.94 S1] Received PDU Response - Proceeding with PDU 240 and 3 max parallel connections.
[18193,247310183] Translation OK
[18193,249174666 192.168.36.94 S1] Preparing to WRITE g0,x0,v0,g1,x1,v1,g2,x2,v2,g3,x3,v3,g4,x4,v4,g5,x5,v5,g6,x6,v6,g7,x7,v7,g8,x8,v8,g9,x9,v9,g10,x10,v10,g11,x11,v11,g12,x12,v12 to value 50,3000,33,21,10000,100,10,30000,100,5,1000,0,20,-22000,75,10,30000,75,20,-22000,75,10,30000,75,20,-22000,75,10,30000,75,10,10000,25,11,0,10,0,0,0
[18193,286220953] PDU type (byte 8) was returned as 2 where the response PDU of 3 was expected.
[18193,288932884] Maybe you are requesting more than 240 bytes of data in a packet?
[18193,292037751] <Buffer 03 00 00 13 02 f0 80 32 02 00 00 00 02 00 00 00 00 85 00>
[18193,294749193] ConnectionReset is happening
[18193,297145409] We Caught a read/write error ECONNRESET - will DISCONNECT and attempt to reconnect.
[18193,300186252] ConnectionReset is happening
[18194,791888445 192.168.36.94 S1] WRITE TIMEOUT on sequence number 2
[18194,798587879] We must have timed Out - we have no response to process
[18194,804174488] Stopping Processing Write Response Packet due to unrecoverable packet error
[18194,814658604 192.168.36.94 S1] WRITE TIMEOUT on sequence number 3
[18194,819903105] We must have timed Out - we have no response to process
[18194,823505981] Stopping Processing Write Response Packet due to unrecoverable packet error
true
[18194,831520084] ResetNOW is happening
[18194,833264341] Clearing an earlier scheduled reset

I want to write to an Array of Struct in DB2. One Struct (line) conatins g: USINT; x: DINT and v: INT. The addresses are map the following way:

    let map = {}
    ;[{g:1,x:2,v:3},...,{g:6,x:7,v:8}].forEach((line, index) => {
        map['g' + index] = [`DB2,BYTE${index * 8}`, line.g]
        map['x' + index] = [`DB2,DINT${index * 8 + 2}`, line.x]
        map['v' + index] = [`DB2,INT${index * 8 + 6}`, line.v]
    })

I can write exactly four lines at a time. One byte more and I get the error.

There is something about 240 byte in the log but 4 * 8 byte = 32 byte is much lower then 240 byte.

I am using a S7 1214 v2.2 CPU.

Datatypes

Hi,
I want to extend the functionality to read/write the remaining basic Datatypes (S5TIME,TIME,CHAR,DATE,TOD). In which places of the src-code do i have to do changes?
Need some hints!!

Thanks

Roadmap to 1.0

Hi @plcpeople and all users of nodeS7,

We all love nodeS7 the project and all the possibilities it opens. The code has been maturing along the last weeks and months, but I see some improvement room to codebase, and therefore I'd like to propose and discuss a roadmap to the version 1.0.0 of this awesome project.

In my personal opinion, in this first milestone I'd like to see (and of course contribute to) a major refactor of the code, separating the logic, creating classes, and organizing the code, without introducing any new feature. This would make it much easier to understand and to maintain, also making it easier to introduce many new features. We could then have more guarantees for the future of the project.

I think we could create a Wiki page or a Project to summarize all the ideas and discuss them, what do you think?

`onISOConnectReply` throwing "write after end"

Hi all,

A problem has been reported on netsmarttech/node-red-contrib-s7, where node eventually throws with the following stack trace:

30 Oct 11:42:37 - [red] Uncaught Exception:
30 Oct 11:42:37 - Error: write after end
    at writeAfterEnd (_stream_writable.js:193:12)
    at Socket.Writable.write (_stream_writable.js:244:5)
    at Socket.write (net.js:658:40)
    at NodeS7.onISOConnectReply (/home/pi/.node-red/node_modules/nodes7/nodeS7.js:306:17)
    at Socket.<anonymous> (/home/pi/.node-red/node_modules/nodes7/nodeS7.js:262:26)
    at emitOne (events.js:96:13)
    at Socket.emit (events.js:188:7)
    at readableAddChunk (_stream_readable.js:176:18)
    at Socket.Readable.push (_stream_readable.js:134:10)
    at TCP.onread (net.js:548:20)

I haven't done a full analysis/reproduction yet, but from the stack trace we can already guess the onISOConnectReply is trying to write on a socket that has been already closed (isoclient.end() has been called)

One of the possibilities I've thought about is, if dropConnection() is called, isoclient.end() is also called and the PLC may eventually send some data. If that would be the state where we're waiting for the ISO connect reply, this might happen.

Have you ever seen this?

s7-200 connection timeout issue

Not able to connect to S7-200 over the IP. Am using a USR IOT device over lan.....

[561172,811872480] Initiate Called - Connecting to PLC with address and parameters:
[561172,813506328] { port: 8899, host: '192.168.100.200', rack: 0, slot: 2 }
[561172,815174310] Connection cleanup is happening
[561172,817187607 192.168.100.200 S2] Attempting to connect to host...
[561172,832953789 192.168.100.200 S2] TCP Connection Established to 192.168.100.200 on port 8899
[561172,833238234 192.168.100.200 S2] Will attempt ISO-on-TCP connection
[561172,834068242 192.168.100.200 S2] Using rack [0] and slot [2]
[561174,338090001 192.168.100.200 S2] TIMED OUT connecting to the PLC - Disconnecting
[561174,338766979 192.168.100.200 S2] Wait for 2 seconds then try again.
[561174,339950267] ConnectionReset is happening
[561174,340925343 192.168.100.200 S2] Scheduling a reconnect from packetTimeout, connect type
[561175,842110622] ResetNOW is happening
[561175,843107315] Clearing an earlier scheduled reset
[561175,874652764 192.168.100.200 S2] ISO-on-TCP connection DISCONNECTED.
Error - TCP connected, ISO didn't

Bug: Request packet sent is bigger than negotiated PDU size

TL;DR
We're not caring about the request packet size. PR suggested

This is the result of the analysis of the following issue: st-one-io/node-red-contrib-s7#10

The issue there says that, although all variables seem to be setup correctly, the read process return "Bad values". With the variable list provided and the logs, I could reproduce the issue locally (with Snap7 acting as the PLC).

With the help of Wireshark, we can take a look at the packets exchanged and I found that, even though the negotiated PDU size was 240 bytes...
image
... nodes7 was requesting a packet bigger than that (in this case, 276 bytes - can be seen in the status bar):
image

Checking on how the packets are created, I saw that care is taken so that the reply is not bigger than the PDU size, but not the request. This usually not the case, but can occur under the following circumstance:

  • The variables span across multiple areas or multiple DBs, so we cannot optimize under a single memory are read operation, and
  • The length being read is very small, so that a whole read command (which has a fixed length of 12 bytes) is bigger than its response (which size is normally data_length + 4), and
  • There are lots of these variables, so we overflow the request packet

I propose to fix this by computing the resulting request packet size, not only the reply one. Then we can split it when the response or when the request would be bigger than the negotiated PDU size. I've implemented this locally and it seems to solve the problem. A PR will follow with this suggestion.

Connection Management Test: Missing ETIMEDOUT under Linux

Description:
I tested the connection management of nodes7 under Windows as well as under Linux. For the test I use keepalive. (Note: Under Linux I use the modul net-keepalive).

Environment:

  1. Windows 10 Pro, [email protected]
  2. Linux (Own Distribution, Kernel Version 4.9.75-rt60-preempt-rt), [email protected]

Tests (Under Linux as well as under Windows.) :
Test case 1:

  • Nothing is done after the connection is established.
  • Cable is removed from PLC
  • After a while the cable is plugged in again.

Test case 2:

  • After connection is established, 'MB0' is read cyclically.
  • Cable is removed from PLC
  • After a while the cable is plugged in again.

Steps to Reproduce:

const NodeS7 = require('nodes7');
let NetKeepAlive = null;
try {
  NetKeepAlive = require('net-keepalive');  // net-keepalive depends on the OS
} catch (er) {
  console.log('Installation of Module net-keepalive failed. (OS=' + process.platform + ')');
  NetKeepAlive = null;
}

const plc = new NodeS7({ debug: 1, silent: false });
const param = { port: 102, host: '192.168.0.111', rack: 0, slot: 2 };

const intervalReading = false; // Set Flag to true/false

plc.initiateConnection(param, (err) => {
  if (typeof (err) !== 'undefined') {
    console.log(err);
    process.exit();
  }

  // Enable KeepAlive.
  plc.isoclient.setKeepAlive(true, 3000);
  if (NetKeepAlive) {
    console.log('Set keepalive parameter for linux.');
    NetKeepAlive.setKeepAliveInterval(plc.isoclient, 3000);
    NetKeepAlive.setKeepAliveProbes(plc.isoclient, 5);
  }

  if (intervalReading) {
    plc.addItems('MB0');
    setInterval(() => {
      console.log('Status: ' + plc.isoConnectionState);
      plc.readAllItems((anythingBad, values) => {
        if (anythingBad) {
          console.log('SOMETHING WENT WRONG READING VALUES!!!!');
        } else {
          console.log(values);
        }
      });
    }, 1000);
  }
});

Expected Behavior:
Test case 1:

  • After successful connection establishment keepalives are exchanged every n sec.
  • If the cable is removed from the PLC, keepalives are not acknowledged
  • After a while Nodes7 changes isoConnectionState from 4 to 0 or 1 due to a reset.
  • Program ends.
  • When the cable is plugged in again nothing happens

Test case 2:

  • After successful connection establishment, cyclic communication starts.
  • If the cable is removed from the PLC, nodes7 attempts a reconnection.
  • nodes7 changes isoConnectionState after a while from 4 to 0 or 1 due to a reset
  • When the cable is plugged in again reconnection nodes7 starts
  • After a while cyclic communication starts again

Actual Behavior:
Overview:

Testcase 1 2
Windows OK OK
Linux OK Not OK

Detailed:
To Testcase 1 (windows): NodeS7 resets Program due to ECONNRESET
To Testcase 2 (windows): NodeS7 resets Program due to ECONNRESET, restarts communication again.

To Testcase 1 (linux): NodeS7 resets Program due to ETIMEDOUT
To Testcase 2 (linux): No reset of nodes7, state always at 4 due to missing ETIMEDOUT, but nodes7 restarts communication again.
I think the state should also go to 0 here.

TCP reconnection.

Hello,
i try to fix an error in case you pull out the cable off the PLC. At some point during the Error process the ISO CS is 0 and the stack tries to reconnect to the PLC again. Perfect, so far. The an (TCP) timeout occures and nothing happens again. Not good.
In my opinion the stack always has to reconnect.
There are two options:
1: Try to reconnect from outside
2: The stack handles the TCP-reconnection. I think it should happen in the function/method connectError

@plcpeople : Do you plan to extend the functionality?
If not...@ all: any idea to implement No.1?

I tried to check the connection via isoConnectionState but i thik it would be way easier to change the lib.

Use questions

Hi, just a few questions from me 😃

I'm planning on including this in a restful API to avoid the need of a SCADA/OPC type 3rd party system and a database to pass information back and forth to a PLC. It's working up to now (Where by I have a basic api with express returning values from my datablock and posting any changes i make from a web front end)

Currently there are lots of outputs from the module, is there a way to turn these off 'in general' not error stuff just the normal information messages or will I have to do this myself? It's just so I don't fill up my logs with unnecessary information or will I have to go through one by one?

Also, instead of process.exit(); that is used in the example I call conn.dropConnection(); I'm concerned the connection is left open once a query has been made. Is this the intended use of this? I get connectionReset logs. If I don't drop the connection I can only make one get request and the ones after just hang, if I call dropConnection I can makes lots of requests in quick succession.

Any help appreciated!
Rogan.

Error on writing Array of Boolean

Hi again,

now I have a problem on writing an Array of Boolean. In reality I need 16bit but for testcase I used 2.

Adress is "DB1,X2.0.2". Write command: plc.writeItems(['boolean'], [[false, true]], ...

Log:

[10622,237878058 192.168.36.94 S1] Preparing to WRITE boolean to value false,true
[10622,292730964] Received write error of 7 on DB1,X2.0.2

2bit_in_Array.pcapng.gz

two consecutive writing request

Thank for you beatiful software.
I'm trying to simulate a pushbutton sending two consecutive request to write 1 and then 0 but there is a error message that I can't write if the previous activity is not completed. Evens using setTimeout with 3000 there is the same message. There is a way to solve?
Thanks
Walter

Error writing Array of boolean

Hi,

found an Error. I declared an Array of Boolean ("DB1,X2.0.16") now I write the values (
[true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
) to the PLC. But the result within the PLC is
[true, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false].

The first 8bit are copied to both bytes.

I tried two other sets:
this:
[true, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false]
results in:
[true, false, true, false, false, false, false, false, true, false, true, false, false, false, false, false]

and this:
[true, false, true, false, false, false, false, false, false, true, false, false, false, false, false, false]
results in:
[true, false, true, false, false, false, false, false, true, true, true, false, false, false, false, false]

Hardware ist still the same. #5

Version is 0.1.8.

Some writing constallations aren't working

Hi,

I evaluated some writing constellations and saw that some are not working:

`conn.writeItems('M0.0', [false], valuesWritten);	//OK
conn.writeItems(['MB0.0'], [false], valuesWritten);	//**Not Working**
conn.writeItems(['M0.0','M0.1','M0.2','M0.3'], [true,true,false,false], valuesWritten);//OK
conn.writeItems('MB0', [7], valuesWritten);		//OK
conn.writeItems(['MB0'], [6], valuesWritten);		//OK
conn.writeItems('MB0.3', [ 1,2,3 ], valuesWritten);	//OK
conn.writeItems(['MB0.3'], [ 2,3,4 ], valuesWritten);	//**Not Working**`

Is this on purpose??

use nodeS7 with browserify

hey,
I'm still a beginner in programming but have become accustomed to it

I would like to use nodes7 to connect a website with a plc.

If someone has a better Idea I am happy about every suggestion.

what I've done so far:
Installation of node, browserify and the modules
create a file with browserify and integrate it into my website

We have an error.  Maybe the PLC is not reachable.Cannot open TCP connection [404]: <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /api/vm/net/connect was not found on this server.</p>
<hr>
<address>Apache/2.4.18 (Ubuntu) Server at 192.168.2.124 Port 80</address>
</body></html>

Maybe someone can help or give me a hint

net-module does't react when pulling of the cable (embedded Linux)

Hallo everyone,

i have a problem that I want to discuss.
The NodeS7-module uses the net-module to create a socket for the whole communication.

I'm reading cyclic values from the plc. To simulate a connection error I pulled off the Ethernet cable. I tested the reaction of my software on three OS. Windows, Ubuntu VM and the destination system an embedded Linux OS. Each of them behave different. The Windows-OS and Ubuntu VM are stopping the communication which is good. In the emb. Linux nothing happens. I debugged the net module to see what's happening in it.

The following picture shows the log-files of each OS.
difference - email

left shell=Windows: after a Timeout of the nodeS7-library the net-module detects an ECONNRESET
middle shell=Ubuntu: after a Timeout of the nodeS7-library the net-module detects an EOF
right shell=embedded Linux: nothing is getting detected

When you have a look on the src-code of the net-module you can see that the debug-log onread is getting created within the onread-function. The on-read function is always called whenever the handle gets a buffer, or when there's an error reading.

Well, I have a reading error. What I am doing wrong???
Any ideas?

Cannot access some addresses on S7 1200

Hi,
We are having trouble reading from some addresses.

watchtables

For the addresses above, we can always read from and write to "MW100" whereas we cannot read from or write to "DB3.DBD0" using same code. When we try to read, the console says "Failed to find a match for DB3".

What are we doing wrong?

Will it work also with Siemens Logo 8?

Hey,

can somebody tell me if it work with a Logo 8?
I testet already but i can't change or read values.
They sad the Logo is online but nothing more.

Thx

Trying to call conn.readAllItems inside setInterval

Here is how I am writing my setInterval call:

var myTimer;
myTimer = setInterval(conn.readAllItems, 2000, function(err, values){
	if(!err){
		callback(null, values);
	}
	else{
		console.log(err);
		callback(err);
	}
})

The callback I reference is in the wrapper function where I am setting the interval. I tried passing it by placing "callback," after the 2000, and before the function(err, values)... but that didn't seem to change anything.

Here is what I get when I try to run it:

[27462038,628543252] Unable to read when not connected. Return bad values.
/home/ssi/nodemonitor/node_modules/nodes7/nodeS7.js:504
        if (self.isWaiting()) {
                 ^
TypeError: Object [object Object] has no method 'isWaiting'

If there is a better way to constantly monitor tags I'm all ears.

Packet Timeout due to Fast Acknowledge

Hi,
currently i have a problem that due to the lovely Fast Acknowledge a timeout occurs.

See:
error
org.txt

Until the “onResponse” function, the communication is alright.

I would we should somehow cancel the timer or re-trigger it here:

nodeS7/nodeS7.js

Line 1088 in 3f70a74

//read again and wait for the requested data

I tried it out with “clearReadPacketTimeouts” but then further communication was not possible anymore. How can I restart the timer?

Write problem with bits

Hello,

at first of all - nodes7 is great !

The only problem i have is to write a bit.
Conntection is OK and read items works fine - REAL, BITS, INT.
Write INT, REAL works also fine.

The only Problem is to write Bits

TEST:'M20.0',
TEST1: 'DB10,X4.0',

For example i use
conn.writeItems('TEST', [true], valuesWritten);

The function valuesWritten bring me a "Done Writing" Message.

Do have a syntax mistake at my variables or at my code?

How do you know the packet content?


    self.connectReq = new Buffer([0x03, 0x00, 0x00, 0x16, 0x11, 0xe0, 0x00, 0x00, 0x00, 0x02, 0x00, 0xc0, 0x01, 0x0a, 0xc1, 0x02, 0x01, 0x00, 0xc2, 0x02, 0x01, 0x02]);
    self.negotiatePDU = new Buffer([0x03, 0x00, 0x00, 0x19, 0x02, 0xf0, 0x80, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x08, 0x00, 0x08, 0x03, 0xc0]);
    self.readReqHeader = new Buffer([0x03, 0x00, 0x00, 0x1f, 0x02, 0xf0, 0x80, 0x32, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x04, 0x01]);
    self.readReq = new Buffer(1500);
    self.writeReqHeader = new Buffer([0x03, 0x00, 0x00, 0x1f, 0x02, 0xf0, 0x80, 0x32, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x05, 0x01]);
    self.writeReq = new Buffer(1500);

Is there a datasheet or it just the profinet protocal?

No right Answer when reading a String

Hello everyone,
i am not 100% shure if this is a bug. I have following issue:
Within my PLC (S7-300) i have a Datablock DB111. Address 0 is parameterized as STRING[12] with the content "SIMATIC--PLC".

When i read out following variables:
var variable = [ 'DB111,CHAR0.14', 'DB111,STRING0.11', 'DB111,STRING1.12', ];

i'll get:
{ 'DB111,CHAR0.14': '\u0000\u0000SIMATIC--PLC', 'DB111,STRING0.11': '', 'DB111,STRING1.12': 'IMATIC--PLC\u0000' }.

Interpretation:
'DB111,CHAR0.14', =>should be alright, two bytes infront of the actual string.
'DB111,STRING0.11', => Wrong
'DB111,STRING1.12',=> For testing purpose

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.