plcpeople / nodeS7

Node.JS library for communication to Siemens S7 PLCs
MIT License
356 stars 120 forks source link

ECONNRESET Nodered #130

Open liulysk opened 1 year ago

liulysk commented 1 year ago

If I don't drop connection I receive:.

[278262,941339600] Translation OK
-----------------Init done-------------
[278262,941464000 11.200.2.63 S1] Unable to read when not connected. Return bad values.
[278262,941554300 11.200.2.63 S1] Adding var0,var1,var2
[278262,941675200 11.200.2.63 S1] Attempting optimization of item DB40,INT2 with DB40,X0.1
[278262,941745300 11.200.2.63 S1] Attempting optimization of item DB40,INT4 with DB40,X0.1
[278262,941878300 11.200.2.63 S1] Not Sending Read Packet because we are not connected - ISO CS is 2
[278262,942123900 11.200.2.63 S1] We Caught a connect error ECONNRESET
Error: read ECONNRESET
    at TCP.onStreamRead (node:internal/stream_base_commons:217:20) {
  errno: -4077,
  code: 'ECONNRESET',
  syscall: 'read'

after a few requests and connection never comes alive.

Is uncommenting lines

//   conn.dropConnection();
//   conn.connectionCleanup();

the only way to keep connection stable? My code

let conn = new nodes7;
let doneReading = false;
let doneWriting = false;

let variables=msg.payload;
let var_names = Object.keys(variables);

conn.initiateConnection({ port: 102, host: '11.200.2.63', rack: 0, slot: 1, debug: true }, connected); // slot 2 for 300/400, slot 1 for 1200/1500, change debug to true to get more info

function connected(err) {
  if (typeof(err) !== "undefined") {
    // We have an error. Maybe the PLC is not reachable.
    console.log(err);
  }
  conn.setTranslationCB(function(tag) { return variables[tag]; }); // This sets the "translation" to allow us to work with object names
  conn.addItems(var_names);
  console.log("-----------------Init done-------------")
  conn.readAllItems(valuesReady);

}

function valuesReady(anythingBad, values) {
  if (anythingBad) { 
      //console.log("SOMETHING WENT WRONG READING VALUES!!!!"); 
      conn.dropConnection(); 
      conn.connectionCleanup();
      node.warn("SOMETHING WENT WRONG READING VALUES!!!!");
  }
  console.log(values);
  msg.payload = values;
  node.send(msg);
  doneReading = true;
//   conn.dropConnection();
//   conn.connectionCleanup();

}

Full nodered subflow:

[{"id":"96b881a14dbfa4a0","type":"subflow","name":"S7 read offset","info":"","category":"","in":[{"x":40,"y":80,"wires":[{"id":"2b484e68cee9678b"}]}],"out":[{"x":620,"y":80,"wires":[{"id":"c75e08ca6ed6f92e","port":0}]}],"env":[],"meta":{},"color":"#DDAA99"},{"id":"c75e08ca6ed6f92e","type":"function","z":"96b881a14dbfa4a0","name":"S7 read","func":"//var nodes7 = require('nodes7'); // This is the package name, if the repository is cloned you may need to require 'nodeS7' with uppercase S\nlet conn = new nodes7;\nlet doneReading = false;\nlet doneWriting = false;\n\nlet variables=msg.payload;\nlet var_names = Object.keys(variables);\n\nconn.initiateConnection({ port: 102, host: '11.200.2.63', rack: 0, slot: 1, debug: true }, connected); // slot 2 for 300/400, slot 1 for 1200/1500, change debug to true to get more info\n// conn.initiateConnection({port: 102, host: '192.168.0.2', localTSAP: 0x0100, remoteTSAP: 0x0200, timeout: 8000, doNotOptimize: true}, connected);\n// local and remote TSAP can also be directly specified instead. The timeout option specifies the TCP timeout.\n\nfunction connected(err) {\n  if (typeof(err) !== \"undefined\") {\n    // We have an error. Maybe the PLC is not reachable.\n    console.log(err);\n    //process.exit();\n  }\n  conn.setTranslationCB(function(tag) { return variables[tag]; }); // This sets the \"translation\" to allow us to work with object names\n  conn.addItems(var_names);\n  console.log(\"-----------------Init done-------------\")\n //  conn.addItems('TEST6');\n  // conn.removeItems(['TEST2', 'TEST3']); // We could do this.\n  // conn.writeItems(['TEST5', 'TEST6'], [ 867.5309, 9 ], valuesWritten); // You can write an array of items as well.\n  // conn.writeItems('TEST7', [666, 777], valuesWritten); // You can write a single array item too.\n//   conn.writeItems('TEST3', true, valuesWritten); // This writes a single boolean item (one bit) to true\n  conn.readAllItems(valuesReady);\n\n}\n\nfunction valuesReady(anythingBad, values) {\n  if (anythingBad) { \n      //console.log(\"SOMETHING WENT WRONG READING VALUES!!!!\"); \n\n      node.warn(\"SOMETHING WENT WRONG READING VALUES!!!!\");\n      conn.dropConnection(); \n      conn.connectionCleanup();\n  }\n  console.log(values);\n  msg.payload = values;\n  node.send(msg);\n  doneReading = true;\n  //process.exit();\n  conn.dropConnection();\n  conn.connectionCleanup();\n  \n//   setTimeout(() => {\n// \tconn.initiateConnection({ port: 102, host: \"192.168.1.2\", rack: 0, slot: 1, debug: true }, connected);\n//   }, 3000);\n//   if (doneWriting) { \n//       node.warn(\"ErrorRead\")\n//       //process.exit(); \n//       }\n}\n\n// function valuesWritten(anythingBad) {\n//   if (anythingBad) { console.log(\"SOMETHING WENT WRONG WRITING VALUES!!!!\"); }\n//   console.log(\"Done writing.\");\n//   doneWriting = true;\n//   if (doneReading) { \n//       node.warn(\"ErrorWrite\")\n//       //process.exit(); \n      \n//   }\n// }\n\n//return msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"nodes7","module":"nodes7"}],"x":440,"y":80,"wires":[[]]},{"id":"2b484e68cee9678b","type":"function","z":"96b881a14dbfa4a0","name":"Create Offset variables","func":"let offset = msg.payload;\nvar new_Obj = {};\n\nlet variables = {\n    \"var0\": \"DB40,X0.1\",\n    \"var1\": \"DB40,INT2\",\n    \"var2\": \"DB40,INT4\",\n    \"var3\": \"DB40,INT6\",\n    \"var4\": \"DB40,INT8\"\n}\n\nlet new_variables = {};\n\nlet offset_addr = [];\n\nlet init_addr = Object.values(variables); //extract variables addresses\n\ninit_addr.forEach((element)=>{\n    let AddrArray = element.split(\",\"); //Split string into memory and address location\n    const regex = /[+-]?\\d+(\\.\\d+)?/g; //extract numbers from string\n    let address = AddrArray[1].match(regex);  // array with found numbers\n    let new_addr_nr = parseFloat(address[0])+offset; //number with offset address\n    \n    const vartype = AddrArray[1].substring(0, AddrArray[1].indexOf(address)); //extract variable type\n    \n    //new variable string\n    let new_addr_str = AddrArray[0]+\",\"+vartype+new_addr_nr.toString();\n    \n    offset_addr.push(new_addr_str)\n});\n\n//Re-map existing keys to new offset values\nObject.keys(variables).forEach(function(key, index) {\n  new_variables[key] = offset_addr[index];\n});\n\n// new_Obj.old = variables;\n// new_Obj.new = new_variables;\n\nmsg.payload = new_variables;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":200,"y":80,"wires":[["c75e08ca6ed6f92e"]]},{"id":"51b3830442babab7","type":"subflow:96b881a14dbfa4a0","z":"d3c43d3a26c0723a","name":"","env":[{"name":"flexdash_grid","value":"","type":"str"}],"x":700,"y":180,"wires":[[]]},{"id":"245f1f869343b198","type":"function","z":"d3c43d3a26c0723a","name":"Offset","func":"msg.payload = 0;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":550,"y":180,"wires":[["51b3830442babab7"]]}]

I'm trying to read multiple identical structures with different offsets. Addressing has to be done dynamically that's why I can't use existing Nodered nodes.

Is there a way to read ~200structures, Max I get stable is ~40. I've tried to connect all in series also. I thought maybe keeping connection alive would help, but I cannot get more calls. image

plcpeople commented 1 year ago

In this code, calling the subflow multiple times creates multiple connections to the PLC and this does not scale well, as the PLC has a maximum number of connections. (If you don't drop the connection, the connection stays open, and a new call creates a new connection, which is why not dropping the connection causes things to fail after a short time) If you want to read a lot of data, this should be done either in series (making sure you finish reading and drop a connection before establishing another) or read everything all at once on one connection which is most efficient. If you want 200 structures, put all the items you want to read in an array first, then add all the items using addItems and it should read them all at once, far more efficiently than with 200 connections.