ads-client
Beckhoff TwinCAT ADS client library for Node.js (unofficial). Connects to Beckhoff TwinCAT automation systems using ADS protocol.
Coded from scratch using TwinCAT ADS specification and Beckhoff.TwinCAT.Ads nuget package. Inspiration from similar projects like node-ads, beckhoff-js and iecstruct.
-There is automatically created documentation available at https://jisotalo.github.io/ads-client/
+There is automatically created documentation available at https://jisotalo.fi/ads-client/
Project status
This project is currently "ready". It's maintained actively and used in projects by the author and others (also lot's of commercial projects)
Bugs are fixed if found and new features can be added. Please let me know if you have any ideas!
-And if you want you can buy me a beer using PayPal :)
- +If you want to support my work, you can do it using PayPal. I can provide you support in exchange.
+ +Version 2
+Version 2 is under development in v2-dev
branch. It's written in TypeScript (including all types!) and will also be more optimized. At the moment basic functions might work but it's not ready for production use.
Using Node-RED?
Check out the node-red-contrib-ads-client package. It's an ads-client
wrapper for Node-RED to get the same functionality.
Table of contents
@@ -177,6 +179,10 @@Installation
Install the npm package using npm command:
npm i ads-client
+If you are using TypeScript, install unofficial types using npm command (thanks Christian Rishøj):
+npm install --save @types/ads-client
+
+Note: Version 2 under development will be written in 100% TypeScript
Include the module in your code
const ads = require('ads-client')
@@ -1656,10 +1662,15 @@ Issues with TwinCAT 2 low-end devices (BK9050, BC9050 etc.)
+-
+
- You can only use raw commands (such as
readRaw()
,writeRaw()
,subscribeRaw()
) as these devices provide no symbols
+ - See issue 114 and issue 116 for starters +
Automatic testing
Since version 1.14.0 the library has automatic testing using Jest. Idea is to run the tests before updates to make sure everything works OK (this should have been done much earlier...)
Separate PLC project is required for testing, see https://github.com/jisotalo/ads-client-test-plc-project for more project and more info.
-Tests are run with command npm test
(not in npm version, please clone this repository).
Tests are run with command npm test
or npm run test-um
(usermode runtime) (not in npm version, please clone this repository).
Documentation
You can find the full html documentation from the project GitHub home page as well as from ./docs/
folder in the repository.
License
@@ -1694,7 +1705,7 @@License
diff --git a/package-lock.json b/package-lock.json index 6e6ab4d..968b984 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ads-client", - "version": "1.14.1", + "version": "1.14.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "ads-client", - "version": "1.14.1", + "version": "1.14.3", "license": "MIT", "dependencies": { "debug": "^4.3.3", @@ -1021,6 +1021,28 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-pTjcqY9E4nOI55Wgpz7eiI8+LzdYnw3qxXCfHyBDdPbYvbyLgWLJGh8EdPvqawwMK1Uo1794AUkkR38Fr0g+2g==", + "dev": true + }, + "node_modules/@types/markdown-it": { + "version": "12.2.3", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", + "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "dev": true, + "dependencies": { + "@types/linkify-it": "*", + "@types/mdurl": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", + "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", + "dev": true + }, "node_modules/@types/node": { "version": "18.0.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.6.tgz", @@ -1520,10 +1542,13 @@ "dev": true }, "node_modules/entities": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", - "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } }, "node_modules/error-ex": { "version": "1.3.2", @@ -2435,9 +2460,9 @@ } }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -2572,31 +2597,32 @@ } }, "node_modules/jsdoc": { - "version": "3.6.7", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.7.tgz", - "integrity": "sha512-sxKt7h0vzCd+3Y81Ey2qinupL6DpRSZJclS04ugHDNmRUXGzqicMJ6iwayhSA0S0DwwX30c5ozyUthr1QKF6uw==", + "version": "3.6.11", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.11.tgz", + "integrity": "sha512-8UCU0TYeIYD9KeLzEcAu2q8N/mx9O3phAGl32nmHlE0LpaJL71mMkP4d+QE5zWfNt50qheHtOZ0qoxVrsX5TUg==", "dev": true, "dependencies": { "@babel/parser": "^7.9.4", + "@types/markdown-it": "^12.2.3", "bluebird": "^3.7.2", "catharsis": "^0.9.0", "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.1", + "js2xmlparser": "^4.0.2", "klaw": "^3.0.0", - "markdown-it": "^10.0.0", - "markdown-it-anchor": "^5.2.7", - "marked": "^2.0.3", + "markdown-it": "^12.3.2", + "markdown-it-anchor": "^8.4.1", + "marked": "^4.0.10", "mkdirp": "^1.0.4", "requizzle": "^0.2.3", "strip-json-comments": "^3.1.0", "taffydb": "2.6.2", - "underscore": "~1.13.1" + "underscore": "~1.13.2" }, "bin": { "jsdoc": "jsdoc.js" }, "engines": { - "node": ">=8.15.0" + "node": ">=12.0.0" } }, "node_modules/jsesc": { @@ -2663,9 +2689,9 @@ "dev": true }, "node_modules/linkify-it": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", - "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", "dev": true, "dependencies": { "uc.micro": "^1.0.1" @@ -2731,14 +2757,14 @@ } }, "node_modules/markdown-it": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", - "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", "dev": true, "dependencies": { - "argparse": "^1.0.7", - "entities": "~2.0.0", - "linkify-it": "^2.0.0", + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", "mdurl": "^1.0.1", "uc.micro": "^1.0.5" }, @@ -2747,30 +2773,37 @@ } }, "node_modules/markdown-it-anchor": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz", - "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==", + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", "dev": true, "peerDependencies": { + "@types/markdown-it": "*", "markdown-it": "*" } }, + "node_modules/markdown-it/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/marked": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-2.1.3.tgz", - "integrity": "sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", "dev": true, "bin": { - "marked": "bin/marked" + "marked": "bin/marked.js" }, "engines": { - "node": ">= 10" + "node": ">= 12" } }, "node_modules/mdurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", "dev": true }, "node_modules/merge-stream": { @@ -3172,9 +3205,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -3368,7 +3401,7 @@ "node_modules/taffydb": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", - "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=", + "integrity": "sha512-y3JaeRSplks6NYQuCOj3ZFMO3j60rTwbuKCvZxsAraGYH2epusatvZ0baZYA01WsGqJBq/Dl6vOrMUJqyMj8kA==", "dev": true }, "node_modules/terminal-link": { @@ -4417,6 +4450,28 @@ "@types/istanbul-lib-report": "*" } }, + "@types/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-pTjcqY9E4nOI55Wgpz7eiI8+LzdYnw3qxXCfHyBDdPbYvbyLgWLJGh8EdPvqawwMK1Uo1794AUkkR38Fr0g+2g==", + "dev": true + }, + "@types/markdown-it": { + "version": "12.2.3", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", + "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "dev": true, + "requires": { + "@types/linkify-it": "*", + "@types/mdurl": "*" + } + }, + "@types/mdurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", + "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==", + "dev": true + }, "@types/node": { "version": "18.0.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.6.tgz", @@ -4797,9 +4852,9 @@ "dev": true }, "entities": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", - "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", "dev": true }, "error-ex": { @@ -5484,9 +5539,9 @@ }, "dependencies": { "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -5594,25 +5649,26 @@ } }, "jsdoc": { - "version": "3.6.7", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.7.tgz", - "integrity": "sha512-sxKt7h0vzCd+3Y81Ey2qinupL6DpRSZJclS04ugHDNmRUXGzqicMJ6iwayhSA0S0DwwX30c5ozyUthr1QKF6uw==", + "version": "3.6.11", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.11.tgz", + "integrity": "sha512-8UCU0TYeIYD9KeLzEcAu2q8N/mx9O3phAGl32nmHlE0LpaJL71mMkP4d+QE5zWfNt50qheHtOZ0qoxVrsX5TUg==", "dev": true, "requires": { "@babel/parser": "^7.9.4", + "@types/markdown-it": "^12.2.3", "bluebird": "^3.7.2", "catharsis": "^0.9.0", "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.1", + "js2xmlparser": "^4.0.2", "klaw": "^3.0.0", - "markdown-it": "^10.0.0", - "markdown-it-anchor": "^5.2.7", - "marked": "^2.0.3", + "markdown-it": "^12.3.2", + "markdown-it-anchor": "^8.4.1", + "marked": "^4.0.10", "mkdirp": "^1.0.4", "requizzle": "^0.2.3", "strip-json-comments": "^3.1.0", "taffydb": "2.6.2", - "underscore": "~1.13.1" + "underscore": "~1.13.2" } }, "jsesc": { @@ -5661,9 +5717,9 @@ "dev": true }, "linkify-it": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", - "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", "dev": true, "requires": { "uc.micro": "^1.0.1" @@ -5717,35 +5773,43 @@ } }, "markdown-it": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", - "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", "dev": true, "requires": { - "argparse": "^1.0.7", - "entities": "~2.0.0", - "linkify-it": "^2.0.0", + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", "mdurl": "^1.0.1", "uc.micro": "^1.0.5" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + } } }, "markdown-it-anchor": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz", - "integrity": "sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA==", + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", "dev": true, "requires": {} }, "marked": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-2.1.3.tgz", - "integrity": "sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", "dev": true }, "mdurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", "dev": true }, "merge-stream": { @@ -6043,9 +6107,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true }, "shebang-command": { @@ -6188,7 +6252,7 @@ "taffydb": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", - "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=", + "integrity": "sha512-y3JaeRSplks6NYQuCOj3ZFMO3j60rTwbuKCvZxsAraGYH2epusatvZ0baZYA01WsGqJBq/Dl6vOrMUJqyMj8kA==", "dev": true }, "terminal-link": { diff --git a/package.json b/package.json index e9a774a..11ab93e 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { "name": "ads-client", - "version": "1.14.2", + "version": "1.14.3", "description": "Beckhoff TwinCAT ADS client library for Node.js (unofficial). Connects to Beckhoff TwinCAT automation systems using ADS protocol.", "main": "./src/ads-client.js", "scripts": { "test": "jest --runInBand", + "test-um": "set ADS_CLIENT_TEST_AMS=192.168.4.1.1.1 && jest --runInBand", "generate-docs": "jsdoc ./src/ads-client.js ./README.md -c ./jsdoc-conf.json -d ./docs/ -t ./node_modules/docdash/" }, "keywords": [ diff --git a/src/ads-client.js b/src/ads-client.js index 4fe7d30..91a3c6c 100644 --- a/src/ads-client.js +++ b/src/ads-client.js @@ -894,7 +894,7 @@ class Client extends EventEmitter { } catch (err) { return reject(new ClientException(this, 'readSymbol()', `Reading symbol ${variableName} failed: Reading data type failed`, err)) } - + //4. Parse the data to javascript object let data = {} try { @@ -3658,7 +3658,7 @@ function _reconnect(forceDisconnect = false, isReconnecting = false) { debug(`_reconnect(): Connection and some subscriptions reinitialized. Connection is back.`) }) - + this.emit('reconnect') resolve(res) @@ -3945,7 +3945,9 @@ async function _onConnectionLost(socketFailure = false) { _console.call(this, 'WARNING: Connection was lost and setting autoReconnect=false. Quiting.') try { await this.disconnect(true) - } catch { } + } catch (err) { + debugD(`_onConnectionLost(): Error during disconnecting. Quiting.`) + } return } @@ -3965,7 +3967,7 @@ async function _onConnectionLost(socketFailure = false) { //Try to reconnect _reconnect.call(this, socketFailure, true) .then(res => { - + //Success -> remove timer _clearTimer(this._internals.reconnectionTimer) @@ -3974,7 +3976,7 @@ async function _onConnectionLost(socketFailure = false) { //Reconnecting failed if (firstTime) _console.call(this, `WARNING: Reconnecting failed. Keeping trying in the background every ${this.settings.reconnectInterval} ms...`) - + //If this is still a valid timer, start over again if (this._internals.reconnectionTimer.id === timerId) { //Creating a new timer with the same id @@ -4018,7 +4020,7 @@ function _clearTimer(timerObject) { //Increasing timer id timerObject.id = timerObject.id < Number.MAX_SAFE_INTEGER ? timerObject.id + 1 : 0; } - + @@ -4294,7 +4296,7 @@ function _systemManagerStatePoller() { let oldState = this.metaData.systemManagerState //If the timer has changed, quit here - if (this._internals.systemManagerStatePoller.id !== timerId){ + if (this._internals.systemManagerStatePoller.id !== timerId) { return } @@ -4353,7 +4355,7 @@ function _systemManagerStatePoller() { () => poller(this._internals.systemManagerStatePoller.id), this.settings.checkStateInterval ) - + } @@ -5241,7 +5243,7 @@ function _parseJsObjectToBuffer(value, dataType, objectPathStr = '', isArraySubI //Struct or array subitem - Go through each subitem if ((dataType.arrayData.length === 0 || isArraySubItem) && dataType.subItems.length > 0) { buffer = Buffer.alloc(dataType.size) - + for (const subItem of dataType.subItems) { //Try the find the subitem from javascript object let key = null @@ -6040,11 +6042,16 @@ function _parseAdsData(packet, data) { case ADS.ADS_COMMAND.ReadWrite: case ADS.ADS_COMMAND.Read: - //0..3 Ads error number ads.errorCode = data.readUInt32LE(pos) pos += 4 + if (data.byteLength <= 4) { + ads.dataLength = 0 + ads.data = Buffer.alloc(0) + break + } + //4..7 Data length (bytes) ads.dataLength = data.readUInt32LE(pos) pos += 4 @@ -6055,8 +6062,6 @@ function _parseAdsData(packet, data) { break - - //-------------- Write --------------- case ADS.ADS_COMMAND.Write: @@ -6066,8 +6071,6 @@ function _parseAdsData(packet, data) { break - - //-------------- Device info --------------- case ADS.ADS_COMMAND.ReadDeviceInfo: @@ -6077,6 +6080,10 @@ function _parseAdsData(packet, data) { ads.data = {} + if (data.byteLength <= 4) { + break + } + //4 Major version ads.data.majorVersion = data.readUInt8(pos) pos += 1 @@ -6094,10 +6101,6 @@ function _parseAdsData(packet, data) { break - - - - //-------------- Device status --------------- case ADS.ADS_COMMAND.ReadState: @@ -6107,6 +6110,10 @@ function _parseAdsData(packet, data) { ads.data = {} + if (data.byteLength <= 4) { + break + } + //4..5 ADS state ads.data.adsState = data.readUInt16LE(pos) ads.data.adsStateStr = ADS.ADS_STATE.toString(ads.data.adsState) @@ -6118,9 +6125,6 @@ function _parseAdsData(packet, data) { break - - - //-------------- Add notification --------------- case ADS.ADS_COMMAND.AddNotification: @@ -6130,15 +6134,16 @@ function _parseAdsData(packet, data) { ads.data = {} + if (data.byteLength <= 4) { + break + } + //4..7 Notification handle ads.data.notificationHandle = data.readUInt32LE(pos) pos += 4 break - - - //-------------- Delete notification --------------- case ADS.ADS_COMMAND.DeleteNotification: @@ -6148,8 +6153,6 @@ function _parseAdsData(packet, data) { break - - //-------------- Notification --------------- case ADS.ADS_COMMAND.Notification: @@ -6157,8 +6160,6 @@ function _parseAdsData(packet, data) { break - - //-------------- WriteControl --------------- case ADS.ADS_COMMAND.WriteControl: @@ -6168,7 +6169,6 @@ function _parseAdsData(packet, data) { break - default: //Unknown command, return a custom error debug(`_parseAdsResponse: Unknown ads command in response: ${packet.ams.adsCommand}`) diff --git a/test/ads-client.test.js b/test/ads-client.test.js index 272b46b..000c47d 100644 --- a/test/ads-client.test.js +++ b/test/ads-client.test.js @@ -25,11 +25,11 @@ SOFTWARE. * This must match with GVL_AdsClientTests.VERSION */ const PLC_PROJECT_VERSION = '1.0.0.0' - const ads = require('../src/ads-client') +const AMS_NET_ID = (process.env['ADS_CLIENT_TEST_AMS'] ?? 'localhost').trim() const client = new ads.Client({ - targetAmsNetId: 'localhost', + targetAmsNetId: AMS_NET_ID, targetAdsPort: 851 }) @@ -44,7 +44,7 @@ describe('connection', () => { test('checking ads client settings', async () => { expect(client).toBeInstanceOf(ads.Client) expect(client).toHaveProperty('settings') - expect(client.settings.targetAmsNetId).toBe('127.0.0.1.1.1') + expect(client.settings.targetAmsNetId).toBe(AMS_NET_ID === 'localhost' ? '127.0.0.1.1.1' : AMS_NET_ID) expect(client.settings.targetAdsPort).toBe(851) })