ads-client 1.14.2 → 1.14.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +20 -5
- package/package.json +2 -1
- package/src/ads-client.js +29 -29
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [1.14.3] - 23.09.2023
|
|
8
|
+
### Changed
|
|
9
|
+
- Bug fix: Some TwinCAT 2 devices (such as BK9050) do not send data length if answering with error code
|
|
10
|
+
- This caused `RangeError: Index out of range` exception as there wasn't enough bytes received
|
|
11
|
+
- See [issue #116](https://github.com/jisotalo/ads-client/issues/116)
|
|
12
|
+
- Bug fix: If using older Node.js versions such as 8.x, connection lost could have caused unhandled exception
|
|
13
|
+
- Reason was `catch {}` which isn't supported in old versions
|
|
14
|
+
- See [issue #116](https://github.com/jisotalo/ads-client/issues/116)
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
- Updated readme to include information about TypeScript types
|
|
18
|
+
- Thanks to [Christian Rishøj](https://github.com/crishoj)
|
|
19
|
+
- Updated readme with FAQ about TwinCAT 2 low-end devices
|
|
20
|
+
- Updated readme about v2 development
|
|
21
|
+
- Added option to run tests with usermode runtime AmsNetId (`192.168.4.1.1.1`) instead of localhost (`npm run test-um`)
|
|
22
|
+
|
|
7
23
|
## [1.14.2] - 02.05.2023
|
|
8
24
|
### Changed
|
|
9
25
|
- Bug fix: `ADS_DATA_TYPE_FLAGS` (`dataType.flags`) were parsed incorrectly.
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
[](https://www.npmjs.org/package/ads-client)
|
|
5
|
-
[](https://www.paypal.com/donate/?business=KUWBXXCVGZZME&no_recurring=0¤cy_code=EUR)
|
|
6
6
|
[](https://github.com/jisotalo/ads-client)
|
|
7
7
|
[](https://choosealicense.com/licenses/mit/)
|
|
8
8
|
|
|
@@ -10,16 +10,19 @@ Beckhoff TwinCAT ADS client library for Node.js (unofficial). Connects to Beckho
|
|
|
10
10
|
|
|
11
11
|
Coded from scratch using [TwinCAT ADS specification](https://infosys.beckhoff.com/content/1033/tc3_ads_intro/116157835.html?id=124964102706356243) and [Beckhoff.TwinCAT.Ads nuget package](https://www.nuget.org/packages/Beckhoff.TwinCAT.Ads/5.0.0-preview6). Inspiration from similar projects like [node-ads](https://www.npmjs.com/package/node-ads), [beckhoff-js](https://www.npmjs.com/package/beckhoff-js) and [iecstruct](https://www.npmjs.com/package/iecstruct).
|
|
12
12
|
|
|
13
|
-
There is automatically created documentation available at https://jisotalo.
|
|
13
|
+
There is automatically created documentation available at https://jisotalo.fi/ads-client/
|
|
14
14
|
|
|
15
15
|
# Project status
|
|
16
16
|
This project is currently "ready". It's maintained actively and used in projects by the author and others (also lot's of commercial projects)
|
|
17
17
|
|
|
18
18
|
Bugs are fixed if found and new features can be added. Please let me know if you have any ideas!
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
If you want to support my work, you can do it using PayPal. I can provide you support in exchange.
|
|
21
21
|
|
|
22
|
-
[](https://www.paypal.com/donate/?business=KUWBXXCVGZZME&no_recurring=0¤cy_code=EUR)
|
|
23
|
+
|
|
24
|
+
## Version 2
|
|
25
|
+
Version 2 is under development in [`v2-dev`](https://github.com/jisotalo/ads-client/tree/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.
|
|
23
26
|
|
|
24
27
|
|
|
25
28
|
# Using Node-RED?
|
|
@@ -101,6 +104,13 @@ Install the [npm package](https://www.npmjs.com/package/ads-client) using npm co
|
|
|
101
104
|
npm i ads-client
|
|
102
105
|
```
|
|
103
106
|
|
|
107
|
+
If you are using TypeScript, install unofficial types using npm command (thanks [Christian Rishøj](https://github.com/crishoj)):
|
|
108
|
+
```bash
|
|
109
|
+
npm install --save @types/ads-client
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
*Note: Version 2 under development will be written in 100% TypeScript*
|
|
113
|
+
|
|
104
114
|
Include the module in your code
|
|
105
115
|
```js
|
|
106
116
|
const ads = require('ads-client')
|
|
@@ -1764,12 +1774,17 @@ Solution:
|
|
|
1764
1774
|
* When closing application, first unsubscribe from all notifications using `unsubscribeAll()`
|
|
1765
1775
|
* Use router instead of direct connection, see https://github.com/jisotalo/ads-client/issues/85#issuecomment-1193098519
|
|
1766
1776
|
|
|
1777
|
+
### Issues with TwinCAT 2 low-end devices (BK9050, BC9050 etc.)
|
|
1778
|
+
* You can only use raw commands (such as `readRaw()`, `writeRaw()`, `subscribeRaw()`) as these devices provide no symbols
|
|
1779
|
+
* See [issue 114](https://github.com/jisotalo/ads-client/issues/114) and [issue 116](https://github.com/jisotalo/ads-client/issues/116) for starters
|
|
1780
|
+
|
|
1781
|
+
|
|
1767
1782
|
# Automatic testing
|
|
1768
1783
|
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...)
|
|
1769
1784
|
|
|
1770
1785
|
Separate PLC project is required for testing, see https://github.com/jisotalo/ads-client-test-plc-project for more project and more info.
|
|
1771
1786
|
|
|
1772
|
-
Tests are run with command `npm test` (not in npm version, please clone this repository).
|
|
1787
|
+
Tests are run with command `npm test` or `npm run test-um` (usermode runtime) (not in npm version, please clone this repository).
|
|
1773
1788
|
|
|
1774
1789
|
# Documentation
|
|
1775
1790
|
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ads-client",
|
|
3
|
-
"version": "1.14.
|
|
3
|
+
"version": "1.14.3",
|
|
4
4
|
"description": "Beckhoff TwinCAT ADS client library for Node.js (unofficial). Connects to Beckhoff TwinCAT automation systems using ADS protocol.",
|
|
5
5
|
"main": "./src/ads-client.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "jest --runInBand",
|
|
8
|
+
"test-um": "set ADS_CLIENT_TEST_AMS=192.168.4.1.1.1 && jest --runInBand",
|
|
8
9
|
"generate-docs": "jsdoc ./src/ads-client.js ./README.md -c ./jsdoc-conf.json -d ./docs/ -t ./node_modules/docdash/"
|
|
9
10
|
},
|
|
10
11
|
"keywords": [
|
package/src/ads-client.js
CHANGED
|
@@ -894,7 +894,7 @@ class Client extends EventEmitter {
|
|
|
894
894
|
} catch (err) {
|
|
895
895
|
return reject(new ClientException(this, 'readSymbol()', `Reading symbol ${variableName} failed: Reading data type failed`, err))
|
|
896
896
|
}
|
|
897
|
-
|
|
897
|
+
|
|
898
898
|
//4. Parse the data to javascript object
|
|
899
899
|
let data = {}
|
|
900
900
|
try {
|
|
@@ -3658,7 +3658,7 @@ function _reconnect(forceDisconnect = false, isReconnecting = false) {
|
|
|
3658
3658
|
|
|
3659
3659
|
debug(`_reconnect(): Connection and some subscriptions reinitialized. Connection is back.`)
|
|
3660
3660
|
})
|
|
3661
|
-
|
|
3661
|
+
|
|
3662
3662
|
this.emit('reconnect')
|
|
3663
3663
|
|
|
3664
3664
|
resolve(res)
|
|
@@ -3945,7 +3945,9 @@ async function _onConnectionLost(socketFailure = false) {
|
|
|
3945
3945
|
_console.call(this, 'WARNING: Connection was lost and setting autoReconnect=false. Quiting.')
|
|
3946
3946
|
try {
|
|
3947
3947
|
await this.disconnect(true)
|
|
3948
|
-
} catch {
|
|
3948
|
+
} catch (err) {
|
|
3949
|
+
debugD(`_onConnectionLost(): Error during disconnecting. Quiting.`)
|
|
3950
|
+
}
|
|
3949
3951
|
|
|
3950
3952
|
return
|
|
3951
3953
|
}
|
|
@@ -3965,7 +3967,7 @@ async function _onConnectionLost(socketFailure = false) {
|
|
|
3965
3967
|
//Try to reconnect
|
|
3966
3968
|
_reconnect.call(this, socketFailure, true)
|
|
3967
3969
|
.then(res => {
|
|
3968
|
-
|
|
3970
|
+
|
|
3969
3971
|
//Success -> remove timer
|
|
3970
3972
|
_clearTimer(this._internals.reconnectionTimer)
|
|
3971
3973
|
|
|
@@ -3974,7 +3976,7 @@ async function _onConnectionLost(socketFailure = false) {
|
|
|
3974
3976
|
//Reconnecting failed
|
|
3975
3977
|
if (firstTime)
|
|
3976
3978
|
_console.call(this, `WARNING: Reconnecting failed. Keeping trying in the background every ${this.settings.reconnectInterval} ms...`)
|
|
3977
|
-
|
|
3979
|
+
|
|
3978
3980
|
//If this is still a valid timer, start over again
|
|
3979
3981
|
if (this._internals.reconnectionTimer.id === timerId) {
|
|
3980
3982
|
//Creating a new timer with the same id
|
|
@@ -4018,7 +4020,7 @@ function _clearTimer(timerObject) {
|
|
|
4018
4020
|
//Increasing timer id
|
|
4019
4021
|
timerObject.id = timerObject.id < Number.MAX_SAFE_INTEGER ? timerObject.id + 1 : 0;
|
|
4020
4022
|
}
|
|
4021
|
-
|
|
4023
|
+
|
|
4022
4024
|
|
|
4023
4025
|
|
|
4024
4026
|
|
|
@@ -4294,7 +4296,7 @@ function _systemManagerStatePoller() {
|
|
|
4294
4296
|
let oldState = this.metaData.systemManagerState
|
|
4295
4297
|
|
|
4296
4298
|
//If the timer has changed, quit here
|
|
4297
|
-
if (this._internals.systemManagerStatePoller.id !== timerId){
|
|
4299
|
+
if (this._internals.systemManagerStatePoller.id !== timerId) {
|
|
4298
4300
|
return
|
|
4299
4301
|
}
|
|
4300
4302
|
|
|
@@ -4353,7 +4355,7 @@ function _systemManagerStatePoller() {
|
|
|
4353
4355
|
() => poller(this._internals.systemManagerStatePoller.id),
|
|
4354
4356
|
this.settings.checkStateInterval
|
|
4355
4357
|
)
|
|
4356
|
-
|
|
4358
|
+
|
|
4357
4359
|
}
|
|
4358
4360
|
|
|
4359
4361
|
|
|
@@ -5241,7 +5243,7 @@ function _parseJsObjectToBuffer(value, dataType, objectPathStr = '', isArraySubI
|
|
|
5241
5243
|
//Struct or array subitem - Go through each subitem
|
|
5242
5244
|
if ((dataType.arrayData.length === 0 || isArraySubItem) && dataType.subItems.length > 0) {
|
|
5243
5245
|
buffer = Buffer.alloc(dataType.size)
|
|
5244
|
-
|
|
5246
|
+
|
|
5245
5247
|
for (const subItem of dataType.subItems) {
|
|
5246
5248
|
//Try the find the subitem from javascript object
|
|
5247
5249
|
let key = null
|
|
@@ -6040,11 +6042,16 @@ function _parseAdsData(packet, data) {
|
|
|
6040
6042
|
case ADS.ADS_COMMAND.ReadWrite:
|
|
6041
6043
|
case ADS.ADS_COMMAND.Read:
|
|
6042
6044
|
|
|
6043
|
-
|
|
6044
6045
|
//0..3 Ads error number
|
|
6045
6046
|
ads.errorCode = data.readUInt32LE(pos)
|
|
6046
6047
|
pos += 4
|
|
6047
6048
|
|
|
6049
|
+
if (data.byteLength <= 4) {
|
|
6050
|
+
ads.dataLength = 0
|
|
6051
|
+
ads.data = Buffer.alloc(0)
|
|
6052
|
+
break
|
|
6053
|
+
}
|
|
6054
|
+
|
|
6048
6055
|
//4..7 Data length (bytes)
|
|
6049
6056
|
ads.dataLength = data.readUInt32LE(pos)
|
|
6050
6057
|
pos += 4
|
|
@@ -6055,8 +6062,6 @@ function _parseAdsData(packet, data) {
|
|
|
6055
6062
|
|
|
6056
6063
|
break
|
|
6057
6064
|
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
6065
|
//-------------- Write ---------------
|
|
6061
6066
|
case ADS.ADS_COMMAND.Write:
|
|
6062
6067
|
|
|
@@ -6066,8 +6071,6 @@ function _parseAdsData(packet, data) {
|
|
|
6066
6071
|
|
|
6067
6072
|
break
|
|
6068
6073
|
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
6074
|
//-------------- Device info ---------------
|
|
6072
6075
|
case ADS.ADS_COMMAND.ReadDeviceInfo:
|
|
6073
6076
|
|
|
@@ -6077,6 +6080,10 @@ function _parseAdsData(packet, data) {
|
|
|
6077
6080
|
|
|
6078
6081
|
ads.data = {}
|
|
6079
6082
|
|
|
6083
|
+
if (data.byteLength <= 4) {
|
|
6084
|
+
break
|
|
6085
|
+
}
|
|
6086
|
+
|
|
6080
6087
|
//4 Major version
|
|
6081
6088
|
ads.data.majorVersion = data.readUInt8(pos)
|
|
6082
6089
|
pos += 1
|
|
@@ -6094,10 +6101,6 @@ function _parseAdsData(packet, data) {
|
|
|
6094
6101
|
|
|
6095
6102
|
break
|
|
6096
6103
|
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
6104
|
//-------------- Device status ---------------
|
|
6102
6105
|
case ADS.ADS_COMMAND.ReadState:
|
|
6103
6106
|
|
|
@@ -6107,6 +6110,10 @@ function _parseAdsData(packet, data) {
|
|
|
6107
6110
|
|
|
6108
6111
|
ads.data = {}
|
|
6109
6112
|
|
|
6113
|
+
if (data.byteLength <= 4) {
|
|
6114
|
+
break
|
|
6115
|
+
}
|
|
6116
|
+
|
|
6110
6117
|
//4..5 ADS state
|
|
6111
6118
|
ads.data.adsState = data.readUInt16LE(pos)
|
|
6112
6119
|
ads.data.adsStateStr = ADS.ADS_STATE.toString(ads.data.adsState)
|
|
@@ -6118,9 +6125,6 @@ function _parseAdsData(packet, data) {
|
|
|
6118
6125
|
|
|
6119
6126
|
break
|
|
6120
6127
|
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
6128
|
//-------------- Add notification ---------------
|
|
6125
6129
|
case ADS.ADS_COMMAND.AddNotification:
|
|
6126
6130
|
|
|
@@ -6130,15 +6134,16 @@ function _parseAdsData(packet, data) {
|
|
|
6130
6134
|
|
|
6131
6135
|
ads.data = {}
|
|
6132
6136
|
|
|
6137
|
+
if (data.byteLength <= 4) {
|
|
6138
|
+
break
|
|
6139
|
+
}
|
|
6140
|
+
|
|
6133
6141
|
//4..7 Notification handle
|
|
6134
6142
|
ads.data.notificationHandle = data.readUInt32LE(pos)
|
|
6135
6143
|
pos += 4
|
|
6136
6144
|
|
|
6137
6145
|
break
|
|
6138
6146
|
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
6147
|
//-------------- Delete notification ---------------
|
|
6143
6148
|
case ADS.ADS_COMMAND.DeleteNotification:
|
|
6144
6149
|
|
|
@@ -6148,8 +6153,6 @@ function _parseAdsData(packet, data) {
|
|
|
6148
6153
|
|
|
6149
6154
|
break
|
|
6150
6155
|
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
6156
|
//-------------- Notification ---------------
|
|
6154
6157
|
case ADS.ADS_COMMAND.Notification:
|
|
6155
6158
|
|
|
@@ -6157,8 +6160,6 @@ function _parseAdsData(packet, data) {
|
|
|
6157
6160
|
|
|
6158
6161
|
break
|
|
6159
6162
|
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
6163
|
//-------------- WriteControl ---------------
|
|
6163
6164
|
case ADS.ADS_COMMAND.WriteControl:
|
|
6164
6165
|
|
|
@@ -6168,7 +6169,6 @@ function _parseAdsData(packet, data) {
|
|
|
6168
6169
|
|
|
6169
6170
|
break
|
|
6170
6171
|
|
|
6171
|
-
|
|
6172
6172
|
default:
|
|
6173
6173
|
//Unknown command, return a custom error
|
|
6174
6174
|
debug(`_parseAdsResponse: Unknown ads command in response: ${packet.ams.adsCommand}`)
|