@machinemetrics/io-adapter-lib 2.32.0

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.
Files changed (264) hide show
  1. package/.circleci/config.yml +141 -0
  2. package/.eslintrc.json +36 -0
  3. package/.gitattributes +12 -0
  4. package/CHANGELOG.md +544 -0
  5. package/README.md +2 -0
  6. package/index.js +17 -0
  7. package/lib/config/adapterConfig.js +535 -0
  8. package/lib/config/common/allowDenyList.js +58 -0
  9. package/lib/config/common/jsonPath.js +44 -0
  10. package/lib/config/common/labjackU3T4Common.js +227 -0
  11. package/lib/config/common/validations.js +142 -0
  12. package/lib/config/configError.js +32 -0
  13. package/lib/config/device/adam-6052Config.js +103 -0
  14. package/lib/config/device/brotherHTTPConfig.js +215 -0
  15. package/lib/config/device/ethernetIPConfig.js +191 -0
  16. package/lib/config/device/ifmIotConfig.js +245 -0
  17. package/lib/config/device/jsonHttpConfig.js +76 -0
  18. package/lib/config/device/labjackT4Config.js +39 -0
  19. package/lib/config/device/labjackT7Config.js +192 -0
  20. package/lib/config/device/labjackU3Config.js +32 -0
  21. package/lib/config/device/modbusTcpConfig.js +336 -0
  22. package/lib/config/device/mqttBaseConfig.js +70 -0
  23. package/lib/config/device/mqttConfig.js +113 -0
  24. package/lib/config/device/mqttLincolnConfig.js +62 -0
  25. package/lib/config/device/mtconnectAdapterConfig.js +42 -0
  26. package/lib/config/device/mtconnectBaseConfig.js +136 -0
  27. package/lib/config/device/mtconnectConfig.js +52 -0
  28. package/lib/config/device/mtconnectHaasConfig.js +15 -0
  29. package/lib/config/device/nullConfig.js +81 -0
  30. package/lib/config/device/opcuaConfig.js +205 -0
  31. package/lib/config/device/pcccConfig.js +88 -0
  32. package/lib/config/engineConfigV1.js +382 -0
  33. package/lib/config/engineConfigV2.js +106 -0
  34. package/lib/config/generator/counterGenConfig.js +15 -0
  35. package/lib/config/generator/cronGenConfig.js +33 -0
  36. package/lib/config/generator/dateTimeGenConfig.js +33 -0
  37. package/lib/config/index.js +339 -0
  38. package/lib/config/transformConfigUtil.js +296 -0
  39. package/lib/engine/dataOutput.js +357 -0
  40. package/lib/engine/deviceOutput.js +186 -0
  41. package/lib/engine/engineV1.js +480 -0
  42. package/lib/engine/engineV2.js +719 -0
  43. package/lib/engine/index.js +34 -0
  44. package/lib/engine/transformBuilderV1.js +111 -0
  45. package/lib/engine/transformBuilderV2.js +74 -0
  46. package/lib/expressionService.js +330 -0
  47. package/lib/math.js +142 -0
  48. package/lib/transform/accumulate.js +98 -0
  49. package/lib/transform/average.js +56 -0
  50. package/lib/transform/debounce.js +152 -0
  51. package/lib/transform/downsample.js +69 -0
  52. package/lib/transform/edge.js +34 -0
  53. package/lib/transform/expression.js +91 -0
  54. package/lib/transform/fallingEdge.js +70 -0
  55. package/lib/transform/fromBuffer.js +89 -0
  56. package/lib/transform/hash.js +41 -0
  57. package/lib/transform/ignoreValue.js +118 -0
  58. package/lib/transform/index.js +93 -0
  59. package/lib/transform/invert.js +25 -0
  60. package/lib/transform/latch.js +99 -0
  61. package/lib/transform/latchValue.js +115 -0
  62. package/lib/transform/logicAnd.js +67 -0
  63. package/lib/transform/logicOr.js +67 -0
  64. package/lib/transform/map.js +115 -0
  65. package/lib/transform/max.js +57 -0
  66. package/lib/transform/maxLength.js +39 -0
  67. package/lib/transform/min.js +57 -0
  68. package/lib/transform/minDelta.js +40 -0
  69. package/lib/transform/offDelay.js +89 -0
  70. package/lib/transform/onDelay.js +89 -0
  71. package/lib/transform/patternEscape.js +24 -0
  72. package/lib/transform/patternMatch.js +194 -0
  73. package/lib/transform/patternReplace.js +170 -0
  74. package/lib/transform/patternTest.js +85 -0
  75. package/lib/transform/rateOfChange.js +56 -0
  76. package/lib/transform/reject.js +115 -0
  77. package/lib/transform/resample.js +96 -0
  78. package/lib/transform/risingEdge.js +90 -0
  79. package/lib/transform/risingEdgeCounter.js +179 -0
  80. package/lib/transform/sampleInterval.js +12 -0
  81. package/lib/transform/source.js +116 -0
  82. package/lib/transform/state.js +201 -0
  83. package/lib/transform/threshold.js +52 -0
  84. package/lib/transform/toBuffer.js +159 -0
  85. package/lib/transform/toggle.js +118 -0
  86. package/lib/transform/transformState.js +193 -0
  87. package/lib/transform/trim.js +27 -0
  88. package/lib/transform/util/chainSource.js +96 -0
  89. package/lib/transform/util/ringBuffer.js +34 -0
  90. package/lib/transform/valueChange.js +34 -0
  91. package/lib/transform/valueDecrease.js +38 -0
  92. package/lib/transform/valueIncrease.js +38 -0
  93. package/lib/transform/valueIncreaseDiff.js +66 -0
  94. package/lib/transform/whenUnavailable.js +73 -0
  95. package/lib/transform/windowCount.js +86 -0
  96. package/lib/util/fileUtil.js +44 -0
  97. package/package.json +38 -0
  98. package/test/.eslintrc.json +15 -0
  99. package/test/chainedTransform.test.js +88 -0
  100. package/test/conditions.test.js +118 -0
  101. package/test/config/ab-pccc.test.js +41 -0
  102. package/test/config/adam-6052.test.js +16 -0
  103. package/test/config/adapter.test.js +109 -0
  104. package/test/config/brother-http.test.js +19 -0
  105. package/test/config/ethernet-ip.test.js +19 -0
  106. package/test/config/ifm-iot.test.js +20 -0
  107. package/test/config/json-http.test.js +47 -0
  108. package/test/config/labjack-t4.test.js +78 -0
  109. package/test/config/labjack-t7.test.js +18 -0
  110. package/test/config/labjack-u3.test.js +17 -0
  111. package/test/config/modbusTcp.test.js +87 -0
  112. package/test/config/mqtt.test.js +19 -0
  113. package/test/config/mqttLincoln.test.js +29 -0
  114. package/test/config/mtconnect.test.js +63 -0
  115. package/test/config/mtconnectAdapter.test.js +124 -0
  116. package/test/config/mtconnectHaas.test.js +15 -0
  117. package/test/config/null.test.js +16 -0
  118. package/test/config/opcua.test.js +97 -0
  119. package/test/config-tests.js +102 -0
  120. package/test/configFiles/conditions.yml +37 -0
  121. package/test/configFiles/data-items-legacy.yml +24 -0
  122. package/test/configFiles/data-items-shorthand.yml +14 -0
  123. package/test/configFiles/data-items.yml +12 -0
  124. package/test/configFiles/device/ab-pccc-default.yml +3 -0
  125. package/test/configFiles/device/ab-pccc-full.yml +13 -0
  126. package/test/configFiles/device/adam-6052-default.yml +2 -0
  127. package/test/configFiles/device/brother-http-default.yml +3 -0
  128. package/test/configFiles/device/ethernet-ip-default.yml +2 -0
  129. package/test/configFiles/device/ifm-iot-default.yml +2 -0
  130. package/test/configFiles/device/json-http-bad-prop.yml +13 -0
  131. package/test/configFiles/device/json-http-bad-prop2.yml +13 -0
  132. package/test/configFiles/device/json-http-default.yml +3 -0
  133. package/test/configFiles/device/json-http-std.yml +13 -0
  134. package/test/configFiles/device/labjack-t4-condition-exprs.yaml +46 -0
  135. package/test/configFiles/device/labjack-t4-default.yml +3 -0
  136. package/test/configFiles/device/labjack-t4-pins-alt.yaml +41 -0
  137. package/test/configFiles/device/labjack-t4-pins.yaml +40 -0
  138. package/test/configFiles/device/labjack-t4-v1.yaml +29 -0
  139. package/test/configFiles/device/labjack-t7-default.yml +2 -0
  140. package/test/configFiles/device/labjack-u3-default.yml +2 -0
  141. package/test/configFiles/device/modbus-partial.yml +4 -0
  142. package/test/configFiles/device/modbus-std-extended.yaml +23 -0
  143. package/test/configFiles/device/modbus-std.yaml +34 -0
  144. package/test/configFiles/device/modbus-tcp-default.yml +3 -0
  145. package/test/configFiles/device/mqtt-default.yml +2 -0
  146. package/test/configFiles/device/mqtt-lincoln-default.yml +3 -0
  147. package/test/configFiles/device/mqtt-lincoln-full.yml +7 -0
  148. package/test/configFiles/device/mtconnect-adapter-default.yml +3 -0
  149. package/test/configFiles/device/mtconnect-adapter-keys.yaml +18 -0
  150. package/test/configFiles/device/mtconnect-complex-keys.yaml +17 -0
  151. package/test/configFiles/device/mtconnect-default.yml +3 -0
  152. package/test/configFiles/device/mtconnect-duplicate-allow-keys.yaml +10 -0
  153. package/test/configFiles/device/mtconnect-duplicate-declare-keys.yaml +8 -0
  154. package/test/configFiles/device/mtconnect-duplicate-deny-keys.yaml +10 -0
  155. package/test/configFiles/device/mtconnect-haas-default.yml +3 -0
  156. package/test/configFiles/device/mtconnect-std.yaml +18 -0
  157. package/test/configFiles/device/null-default.yml +1 -0
  158. package/test/configFiles/device/opcua-bad-tag.yml +18 -0
  159. package/test/configFiles/device/opcua-bad-tag2.yml +18 -0
  160. package/test/configFiles/device/opcua-default.yml +3 -0
  161. package/test/configFiles/device/opcua-std.yml +18 -0
  162. package/test/configFiles/dump-test.yml +11 -0
  163. package/test/configFiles/expressionCond.yml +46 -0
  164. package/test/configFiles/min-config-t4.yaml +4 -0
  165. package/test/configFiles/min-config-u3.yaml +3 -0
  166. package/test/configFiles/missing-device.yaml +2 -0
  167. package/test/configFiles/parse-error1.yml +9 -0
  168. package/test/configFiles/parse-error2.yml +9 -0
  169. package/test/configFiles/repro/buffer-convert-repro.yml +15 -0
  170. package/test/configFiles/repro/chained-delay-timing-repro.yml +13 -0
  171. package/test/configFiles/repro/count-init-repro.yml +45 -0
  172. package/test/configFiles/repro/cycle-break-repro.yml +44 -0
  173. package/test/configFiles/repro/debounce-repro.yml +46 -0
  174. package/test/configFiles/repro/diff-count-repro.yml +34 -0
  175. package/test/configFiles/repro/engine-hang-repro.yml +9 -0
  176. package/test/configFiles/repro/latch-apm-repro.yml +26 -0
  177. package/test/configFiles/repro/lockout-count-repro.yml +33 -0
  178. package/test/configFiles/repro/program-extract-repro.yml +38 -0
  179. package/test/configFiles/repro/state-latch-repro.yml +47 -0
  180. package/test/configFiles/repro/ternary-repro.yml +26 -0
  181. package/test/configFiles/transform/debounce.yml +12 -0
  182. package/test/configFiles/transform/expression.yml +34 -0
  183. package/test/configFiles/transform/ignoreValue.yml +31 -0
  184. package/test/configFiles/transform/latch.yml +11 -0
  185. package/test/configFiles/transform/latchValue.yml +31 -0
  186. package/test/configFiles/transform/logicAnd.yml +14 -0
  187. package/test/configFiles/transform/logicOr.yml +14 -0
  188. package/test/configFiles/transform/map.yml +19 -0
  189. package/test/configFiles/transform/maxLength.yml +13 -0
  190. package/test/configFiles/transform/offDelay.yml +12 -0
  191. package/test/configFiles/transform/pattern-escape.yml +10 -0
  192. package/test/configFiles/transform/pattern-match.yml +57 -0
  193. package/test/configFiles/transform/pattern-replace.yml +34 -0
  194. package/test/configFiles/transform/pattern-test.yml +25 -0
  195. package/test/configFiles/transform/reject.yml +24 -0
  196. package/test/configFiles/transform/risingEdgeCounter.yml +36 -0
  197. package/test/configFiles/transform/source.yml +20 -0
  198. package/test/configFiles/transform/state.yml +56 -0
  199. package/test/configFiles/transform/toggle.yml +19 -0
  200. package/test/configFiles/transform/whenUnavailable.yml +19 -0
  201. package/test/dataFiles/noisy-pulse.txt +11330 -0
  202. package/test/dataItems.test.js +140 -0
  203. package/test/engine-v1-tests.js +418 -0
  204. package/test/engine-v2-tests.js +284 -0
  205. package/test/expression-tests.js +171 -0
  206. package/test/expressionService.test.js +154 -0
  207. package/test/expressionServiceCondition.test.js +130 -0
  208. package/test/repro/buffer-convert-repro.test.js +38 -0
  209. package/test/repro/chained-delay-timing-repro.test.js +34 -0
  210. package/test/repro/count-init-repro.test.js +46 -0
  211. package/test/repro/cylce-break-repro.test.js +57 -0
  212. package/test/repro/debounce-repro.test.js +65 -0
  213. package/test/repro/diff-count-repro.test.js +79 -0
  214. package/test/repro/engine-hang-repro.test.js +38 -0
  215. package/test/repro/latch-apm-repro.test.js +119 -0
  216. package/test/repro/lockout-count-repro.test.js +84 -0
  217. package/test/repro/program-extract-repro.test.js +40 -0
  218. package/test/repro/state-latch-repro.test.js +63 -0
  219. package/test/repro/ternary-repro.test.js +43 -0
  220. package/test/transform/accumulte.test.js +18 -0
  221. package/test/transform/average.test.js +22 -0
  222. package/test/transform/debounce.test.js +70 -0
  223. package/test/transform/downsample.test.js +30 -0
  224. package/test/transform/edge.test.js +27 -0
  225. package/test/transform/expression.test.js +189 -0
  226. package/test/transform/fallingEdge.test.js +59 -0
  227. package/test/transform/fromBuffer.test.js +60 -0
  228. package/test/transform/hash.test.js +34 -0
  229. package/test/transform/ignoreValue.test.js +123 -0
  230. package/test/transform/invert.test.js +26 -0
  231. package/test/transform/latch.test.js +33 -0
  232. package/test/transform/latchValue.test.js +126 -0
  233. package/test/transform/logicAnd.test.js +80 -0
  234. package/test/transform/logicOr.test.js +80 -0
  235. package/test/transform/map.test.js +42 -0
  236. package/test/transform/max.test.js +30 -0
  237. package/test/transform/maxLength.test.js +32 -0
  238. package/test/transform/min.test.js +30 -0
  239. package/test/transform/minDelta.test.js +14 -0
  240. package/test/transform/offDelay.test.js +123 -0
  241. package/test/transform/onDelay.test.js +105 -0
  242. package/test/transform/patternEscape.test.js +18 -0
  243. package/test/transform/patternMatch.test.js +177 -0
  244. package/test/transform/patternReplace.test.js +95 -0
  245. package/test/transform/patternTest.test.js +105 -0
  246. package/test/transform/rateOfChange.test.js +34 -0
  247. package/test/transform/reject.test.js +56 -0
  248. package/test/transform/resample.test.js +193 -0
  249. package/test/transform/risingEdge.test.js +60 -0
  250. package/test/transform/risingEdgeCounter.test.js +227 -0
  251. package/test/transform/sampleInterval.test.js +22 -0
  252. package/test/transform/source.test.js +137 -0
  253. package/test/transform/state.test.js +248 -0
  254. package/test/transform/threshold.test.js +78 -0
  255. package/test/transform/toBuffer.test.js +60 -0
  256. package/test/transform/toggle.test.js +92 -0
  257. package/test/transform/trim.test.js +30 -0
  258. package/test/transform/valueChange.test.js +14 -0
  259. package/test/transform/valueDecrease.test.js +32 -0
  260. package/test/transform/valueIncrease.test.js +32 -0
  261. package/test/transform/valueIncreaseDiff.test.js +32 -0
  262. package/test/transform/whenUnavailable.test.js +93 -0
  263. package/test/transform/windowCount.test.js +26 -0
  264. package/test/util/testUtils.js +405 -0
@@ -0,0 +1,124 @@
1
+ 'use strict';
2
+
3
+ const _ = require('lodash');
4
+ const expect = require('chai').expect;
5
+ const ConfigError = require('../../lib/config/configError');
6
+ const testUtils = require('../util/testUtils');
7
+
8
+ describe('MTConnect Adapter config tests', function () {
9
+ let config;
10
+ let complexConfig;
11
+ let defaultConfig;
12
+
13
+ before(async () => {
14
+ defaultConfig = await testUtils.loadConfig('device/mtconnect-adapter-default.yml');
15
+ config = await testUtils.loadConfig('device/mtconnect-adapter-keys.yaml');
16
+ complexConfig = await testUtils.loadConfig('device/mtconnect-complex-keys.yaml');
17
+ });
18
+
19
+ it('loads minimal config with defaults', async function () {
20
+ expect(defaultConfig.device.host).to.eq('machine.local');
21
+ expect(defaultConfig.device.port).to.eq(7878);
22
+ expect(defaultConfig.device.mtconnectPassthrough).to.eq(true);
23
+ expect(defaultConfig.device.allowKeyPatterns).to.deep.eq([]);
24
+ expect(defaultConfig.device.denyKeyPatterns).to.deep.eq([]);
25
+ expect(defaultConfig.device.keys).to.deep.eq([]);
26
+ expect(defaultConfig.device.sourceKeys).to.deep.eq([]);
27
+ });
28
+
29
+ it('reads declare-keys', async function () {
30
+ expect(_.keys(config.device.keys)).to.deep.eq(['key1', 'key12']);
31
+ });
32
+
33
+ it('handles allow-keys patterns', async function () {
34
+ testPatternSet(config.device.allowKeyPatterns);
35
+ });
36
+
37
+ it('handles deny-keys patterns', async function () {
38
+ testPatternSet(config.device.denyKeyPatterns);
39
+ });
40
+
41
+ it('loaded expression service', async function () {
42
+ expect(config.expressionService.definedNames()).to.deep.eq(['key1', 'key12', 'device-connected']);
43
+ expect(config.expressionService.definedNames('device')).to.deep.eq(['key1', 'key12']);
44
+
45
+ expect(complexConfig.expressionService.definedNames()).to.deep.eq(['key1', 'alias2', 'alias3', 'alias4', 'alias5', 'key6', 'aliasdup', 'device-connected']);
46
+ });
47
+
48
+ it('calculates source keys', async function () {
49
+ expect(_.keys(complexConfig.device.keys)).to.deep.eq(['key1', 'alias2', 'alias3', 'alias4', 'alias5', 'key6', 'aliasdup']);
50
+ expect(complexConfig.device.sourceKeys).to.deep.eq(['key1', 'key2', 'key3', 'key4', 'key5', 'key6']);
51
+ });
52
+
53
+ it('creates aliases', async function () {
54
+ expect(_.keys(complexConfig.device.aliasMap)).to.deep.eq(['key1', 'key2', 'key3', 'key4', 'key5', 'key6']);
55
+
56
+ expect(complexConfig.device.aliasMap.key1).to.deep.eq([]);
57
+ expect(complexConfig.device.aliasMap.key2).to.deep.eq(['alias2']);
58
+ expect(complexConfig.device.aliasMap.key3).to.deep.eq(['alias3', 'aliasdup']);
59
+ expect(complexConfig.device.aliasMap.key4).to.deep.eq(['alias4']);
60
+ expect(complexConfig.device.aliasMap.key5).to.deep.eq(['alias5']);
61
+ expect(complexConfig.device.aliasMap.key6).to.deep.eq([]);
62
+ });
63
+
64
+ it('sets key types', async function () {
65
+ expect(complexConfig.device.keys.key1.type).to.eq('value');
66
+ expect(complexConfig.device.keys.alias2.type).to.eq('value');
67
+ expect(complexConfig.device.keys.alias3.type).to.eq('value');
68
+ expect(complexConfig.device.keys.alias4.type).to.eq('value');
69
+ expect(complexConfig.device.keys.alias5.type).to.eq('condition');
70
+ expect(complexConfig.device.keys.key6.type).to.eq('condition');
71
+ });
72
+
73
+ it('throws error for duplicate declare-keys', async function () {
74
+ try {
75
+ await testUtils.loadConfig('device/mtconnect-duplicate-declare-keys.yaml');
76
+ expect.fail('Configuration with duplicate declare-keys should have thrown an error');
77
+ } catch (err) {
78
+ expect(err).to.be.instanceof(ConfigError);
79
+ expect(err.attribute).to.eq('declare-keys');
80
+ expect(err.message).to.include('duplicate key names found: key1');
81
+ }
82
+ });
83
+
84
+ it('throws error for duplicate allow-keys', async function () {
85
+ try {
86
+ await testUtils.loadConfig('device/mtconnect-duplicate-allow-keys.yaml');
87
+ expect.fail('Configuration with duplicate allow-keys should have thrown an error');
88
+ } catch (err) {
89
+ expect(err).to.be.instanceof(ConfigError);
90
+ expect(err.attribute).to.eq('allow-keys');
91
+ expect(err.message).to.include('duplicate entries found: system');
92
+ }
93
+ });
94
+
95
+ it('throws error for duplicate deny-keys', async function () {
96
+ try {
97
+ await testUtils.loadConfig('device/mtconnect-duplicate-deny-keys.yaml');
98
+ expect.fail('Configuration with duplicate deny-keys should have thrown an error');
99
+ } catch (err) {
100
+ expect(err).to.be.instanceof(ConfigError);
101
+ expect(err.attribute).to.eq('deny-keys');
102
+ expect(err.message).to.include('duplicate entries found: system');
103
+ }
104
+ });
105
+ });
106
+
107
+ function testPatternSet(set) {
108
+ expect(set.length).to.eq(5);
109
+ expect(set[0].test('system')).to.eq(true);
110
+ expect(set[0].test('system1')).to.eq(false);
111
+ expect(set[1].test('block')).to.eq(true);
112
+ expect(set[1].test('block12')).to.eq(true);
113
+ expect(set[1].test('Block12')).to.eq(false);
114
+ expect(set[1].test('xblock12')).to.eq(false);
115
+ expect(set[2].test('dim1x2')).to.eq(true);
116
+ expect(set[2].test('dim1y2')).to.eq(false);
117
+ expect(set[3].test('xpos')).to.eq(true);
118
+ expect(set[3].test('XPos')).to.eq(false);
119
+ expect(set[3].test('ypos2')).to.eq(true);
120
+ expect(set[3].test('wpos')).to.eq(false);
121
+ expect(set[3].test('xpos1a')).to.eq(false);
122
+ expect(set[4].test('xpos')).to.eq(true);
123
+ expect(set[4].test('XPos')).to.eq(true);
124
+ }
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ const expect = require('chai').expect;
4
+ const testUtils = require('../util/testUtils');
5
+
6
+ describe('MTConnect Haas config tests', function () {
7
+ let config;
8
+ before(async () => {
9
+ config = await testUtils.loadConfig('device/mtconnect-haas-default.yml');
10
+ });
11
+
12
+ it('Sets port 8082 as the default port if not specified', async function () {
13
+ expect(config.device.endpoint).to.eq('http://localhost:8082/');
14
+ });
15
+ });
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ const expect = require('chai').expect;
4
+ const testUtils = require('../util/testUtils');
5
+
6
+ describe('Null (Local) config tests', function () {
7
+ let defaultConfig;
8
+ before(async () => {
9
+ defaultConfig = await testUtils.loadConfig('device/null-default.yml');
10
+ });
11
+
12
+ it('reads default config', async function () {
13
+ expect(defaultConfig.device.keys).to.deep.eq([]);
14
+ expect(defaultConfig.device.sourceKeys).to.deep.eq([]);
15
+ });
16
+ });
@@ -0,0 +1,97 @@
1
+ 'use strict';
2
+
3
+ const _ = require('lodash');
4
+ const expect = require('chai').expect;
5
+ const testUtils = require('../util/testUtils');
6
+
7
+ describe('OPC-UA config tests', function () {
8
+ let config;
9
+ let defaultConfig;
10
+ before(async () => {
11
+ defaultConfig = await testUtils.loadConfig('device/opcua-default.yml');
12
+ config = await testUtils.loadConfig('device/opcua-std.yml');
13
+ });
14
+
15
+ it('loads minimal config with defaults', async function () {
16
+ expect(defaultConfig.device.securityMode).to.eq('None');
17
+ expect(defaultConfig.device.securityPolicy).to.eq('None');
18
+ expect(defaultConfig.device.readMode).to.eq('subscription');
19
+ expect(defaultConfig.device.forceReadOnConnect).to.eq(false);
20
+ expect(defaultConfig.device.scanInterval).to.eq(1000);
21
+ expect(defaultConfig.device.tags).to.deep.eq({});
22
+ expect(defaultConfig.device.username).to.eq(undefined);
23
+ expect(defaultConfig.device.password).to.eq(undefined);
24
+ expect(defaultConfig.device.userCertificatePath).to.eq(undefined);
25
+ expect(defaultConfig.device.userPrivateKeyPath).to.eq(undefined);
26
+ expect(defaultConfig.device.conditionKey).to.eq(undefined);
27
+ });
28
+
29
+ it('reads tags', async function () {
30
+ expect(_.keys(config.device.tags)).to.deep.eq(['fan-speed', 'pump-speed', 'some-date', 'pressure']);
31
+ });
32
+
33
+ it('loaded expression service', async function () {
34
+ const deviceNames = ['fan-speed', 'pump-speed', 'some-date', 'pressure'];
35
+ const allNames = [...deviceNames, 'device-connected'];
36
+ expect(config.expressionService.definedNames()).to.deep.eq(allNames);
37
+ expect(config.expressionService.definedNames('device')).to.deep.eq(deviceNames);
38
+
39
+ expect(config.expressionService.referencedNames()).to.deep.eq(['fan-speed', 'pump-speed']);
40
+ expect(config.expressionService.referencedNames('device')).to.deep.eq(['fan-speed', 'pump-speed']);
41
+ });
42
+
43
+ it('catches bad tag definition (bad path syntax)', async function () {
44
+ try {
45
+ await testUtils.loadConfig('device/opcua-bad-tag.yml');
46
+ throw new Error('Malformed tag accepted');
47
+ } catch (err) {
48
+ expect(err.section).to.deep.eq(['tags']);
49
+ expect(err.attribute).to.eq('fan-speed');
50
+ expect(err.message.indexOf('Malformed tag definition')).to.eq(0);
51
+ }
52
+ });
53
+
54
+ it('catches bad tag definition (missing path)', async function () {
55
+ try {
56
+ await testUtils.loadConfig('device/opcua-bad-tag2.yml');
57
+ throw new Error('Malformed tag accepted');
58
+ } catch (err) {
59
+ expect(err.section).to.deep.eq(['tags', 'fan-speed']);
60
+ expect(err.message.indexOf('no path specified')).to.eq(0);
61
+ }
62
+ });
63
+
64
+ it('accepts valid node id paths', async function () {
65
+ expect(config.device.checkTagPath({ path: 'ns=2;i=10853' })).to.eq('ns=2;i=10853');
66
+ expect(config.device.checkTagPath({ path: 'ns=2;s=someIdentifier' })).to.eq('ns=2;s=someIdentifier');
67
+ expect(config.device.checkTagPath({ path: 'ns=2;g=BAEAF004-1E43-4A06-9EF0-E52010D5CD10' })).to.eq('ns=2;g=BAEAF004-1E43-4A06-9EF0-E52010D5CD10');
68
+ expect(config.device.checkTagPath({ path: 'ns=2;b=AP8=' })).to.eq('ns=2;b=AP8=');
69
+ expect(config.device.checkTagPath({ path: 'i=10853' })).to.eq('i=10853');
70
+ expect(config.device.checkTagPath({ path: 's=someIdentifier' })).to.eq('s=someIdentifier');
71
+ expect(config.device.checkTagPath({ path: 'g=BAEAF004-1E43-4A06-9EF0-E52010D5CD10' })).to.eq('g=BAEAF004-1E43-4A06-9EF0-E52010D5CD10');
72
+ expect(config.device.checkTagPath({ path: 'b=AP8=' })).to.eq('b=AP8=');
73
+ });
74
+
75
+ it('accepts valid indexes', async function () {
76
+ expect(config.device.checkIndex({ index: '5' })).to.include({ start: 5, end: 5 });
77
+ expect(config.device.checkIndex({ index: '5:8' })).to.include({ start: 5, end: 8 });
78
+ expect(config.device.checkIndex({ })).to.equal(null);
79
+ });
80
+
81
+ it('rejects invalid node id paths', async function () {
82
+ const testPath = (path) => {
83
+ try {
84
+ config.device.checkTagPath({ path });
85
+ throw new Error('Malformed tag accepted');
86
+ } catch (err) {
87
+ expect(err.message).to.not.eq('Malformed tag accepted');
88
+ }
89
+ };
90
+
91
+ testPath('ns=2; i=10853');
92
+ testPath('ns=2;i=abcd');
93
+ testPath('ns=2;j=10853');
94
+ testPath('10853');
95
+ testPath('nsu=http://test.org/UA/Data/;i=10853');
96
+ });
97
+ });
@@ -0,0 +1,102 @@
1
+ 'use strict';
2
+
3
+ /* eslint-disable no-unused-vars */
4
+
5
+ const _ = require('lodash');
6
+ const expect = require('chai').expect;
7
+ const ConfigError = require('../lib/config/configError');
8
+ const testUtils = require('./util/testUtils');
9
+
10
+ describe('Config tests', function () {
11
+ it('loads a minimum U3 config', async function () {
12
+ const config = await testUtils.loadConfig('min-config-u3.yaml');
13
+ expect(config.configVersion).to.eq(1);
14
+ expect(config.engineVersion).to.eq(1);
15
+ expect(config.deviceName).to.eq('labjack-u3');
16
+ expect(config.port).to.eq(8001);
17
+
18
+ expect(config.device.scanInterval).to.eq(0.002);
19
+ expect(_.size(config.device.pins)).to.eq(34);
20
+ });
21
+
22
+ it('loads a minimum T4 config', async function () {
23
+ const config = await testUtils.loadConfig('min-config-t4.yaml');
24
+ expect(config.configVersion).to.eq(1);
25
+ expect(config.engineVersion).to.eq(1);
26
+ expect(config.deviceName).to.eq('labjack-t4');
27
+ expect(config.port).to.eq(8001);
28
+
29
+ expect(config.device.host).to.eq('192.168.1.100');
30
+ expect(config.device.scanInterval).to.eq(0.002);
31
+ expect(_.size(config.device.pins)).to.eq(34);
32
+ });
33
+
34
+ it('fails to load missing device', async function () {
35
+ try {
36
+ const config = await testUtils.loadConfig('missing-device.yaml');
37
+ expect.fail();
38
+ } catch (err) {
39
+ expect(err).to.be.instanceof(ConfigError);
40
+ }
41
+ });
42
+
43
+ it('load handles injection option (object)', async function () {
44
+ const inject = {
45
+ device: 'labjack-t4',
46
+ 'mtconnect-port': 8002,
47
+ };
48
+ const config = await testUtils.loadConfig('device/modbus-partial.yml', { inject });
49
+
50
+ expect(config.deviceName).to.eq('modbus-tcp'); // config file takes precedence
51
+ expect(config.port).to.eq(8002);
52
+ });
53
+
54
+ it('load handles injection option (string)', async function () {
55
+ const inject = 'device: labjack-t4\nmtconnect-port: 8002\n';
56
+ const config = await testUtils.loadConfig('device/modbus-partial.yml', { inject });
57
+
58
+ expect(config.deviceName).to.eq('modbus-tcp'); // config file takes precedence
59
+ expect(config.port).to.eq(8002);
60
+ });
61
+
62
+ it('dump returns preserved yaml', async function () {
63
+ const inject = 'version: 1\ndevice: modbus-tcp\nhost: localhost\nmtconnect-port: 8002\n';
64
+ const config = await testUtils.loadConfig('dump-test.yml', { inject });
65
+
66
+ const expectedOutput = `version: 2
67
+ # registers
68
+ registers:
69
+ test: # test register
70
+ address: 30001
71
+ type: uint16
72
+
73
+ # output
74
+ data-items:
75
+ test:
76
+ value: "test"
77
+ device: modbus-tcp
78
+ host: localhost
79
+ mtconnect-port: 8002
80
+ `;
81
+
82
+ expect(config.dumpYaml()).to.eq(expectedOutput);
83
+ });
84
+
85
+ it('parse error', async function () {
86
+ try {
87
+ await testUtils.loadConfig('parse-error1.yml');
88
+ throw new Error('Document parsed without error');
89
+ } catch (err) {
90
+ expect(err.message.indexOf('YAML Error (lines 6 - 8): Nested mappings')).to.eq(0);
91
+ }
92
+ });
93
+
94
+ it('parse error', async function () {
95
+ try {
96
+ await testUtils.loadConfig('parse-error2.yml');
97
+ throw new Error('Document parsed without error');
98
+ } catch (err) {
99
+ expect(err.message.indexOf('YAML Error (lines 1 - 9): All collection items')).to.eq(0);
100
+ }
101
+ });
102
+ });
@@ -0,0 +1,37 @@
1
+ version: 2
2
+ device: local
3
+ declare-keys:
4
+ - key1
5
+ - key2
6
+ - key3
7
+ - key4
8
+ variables:
9
+ keymod:
10
+ - source: key2
11
+ - threshold: 3
12
+ conditions:
13
+ cond1:
14
+ - code: A1
15
+ message: Code A1
16
+ value:
17
+ FAULT: key1 > 10
18
+ WARNING: key1 > 5
19
+ - code: A2
20
+ message: Code A2
21
+ value:
22
+ FAULT: keymod
23
+ cond2:
24
+ - code: B${key3}
25
+ message: Code B${key3}
26
+ value:
27
+ FAULT: key1 > 10
28
+ cond3:
29
+ source: key4
30
+ overrides:
31
+ - match-code: /X\d+/
32
+ override-code: E${this}
33
+ override-message: Extra ${this}
34
+ - match-message: /.*coolant.*/
35
+ override-message: ${this} coolant=${key1}
36
+ - override-code: Y
37
+ override-message: Z
@@ -0,0 +1,24 @@
1
+ version: 2
2
+ device: local
3
+ declare-keys:
4
+ - key1
5
+ - key2
6
+ variables:
7
+ keymod:
8
+ - source: key2
9
+ - threshold: 3
10
+ data-items:
11
+ key1:
12
+ value: key1
13
+ key1a:
14
+ value: key1 + 5
15
+ key1b:
16
+ value: key1 + key2
17
+ key2a:
18
+ value:
19
+ ACTIVE: keymod
20
+ READY: true
21
+ key2b:
22
+ value:
23
+ ACTIVE: key2 > 3
24
+ READY: true
@@ -0,0 +1,14 @@
1
+ version: 2
2
+ device: local
3
+ declare-keys:
4
+ - key1
5
+ - key2
6
+ - key3
7
+ variables:
8
+ keymod: key2 >= 3
9
+ data-items:
10
+ - key1
11
+ - key2: key2
12
+ - key2a: keymod
13
+ - key2b: key2 + key3.speed
14
+ - key3: key3.position
@@ -0,0 +1,12 @@
1
+ version: 2
2
+ device: local
3
+ declare-keys:
4
+ - key1
5
+ - key2
6
+ variables:
7
+ keymod:
8
+ - source: key2
9
+ - threshold: 3
10
+ data-items:
11
+ - key1
12
+ - keymod
@@ -0,0 +1,3 @@
1
+ version: 2
2
+ device: ab-pccc
3
+ endpoint: 192.168.1.150
@@ -0,0 +1,13 @@
1
+ version: 2
2
+ device: ab-pccc
3
+ endpoint: 192.168.1.150:1234
4
+ scan-interval: 0.1
5
+ routing: true
6
+ verbose-device: true
7
+ extra-verbose-device: true
8
+ device-timeout: 10
9
+ slot: 1
10
+ tags:
11
+ tag1: F7:5
12
+ tag2: B12:3/5
13
+ tag3: ST3:1,4
@@ -0,0 +1,2 @@
1
+ device: adam-6052
2
+ host: 192.168.1.100
@@ -0,0 +1,3 @@
1
+ device: brother-http
2
+ endpoint: 192.168.1.100
3
+ collection-mode: http
@@ -0,0 +1,2 @@
1
+ device: ethernet-ip
2
+ host: 192.168.1.100
@@ -0,0 +1,2 @@
1
+ device: iolink-ifm-iot
2
+ endpoint: 192.168.1.100
@@ -0,0 +1,13 @@
1
+ version: 2
2
+ device: json-http
3
+ endpoint: http://localhost:5000
4
+ props:
5
+ file: file
6
+ part_number: part_number
7
+ process_status:
8
+ path: 0.processStatus[test=5..test
9
+ route: /process
10
+ data-items:
11
+ - file
12
+ - part_number
13
+ - process_status
@@ -0,0 +1,13 @@
1
+ version: 2
2
+ device: json-http
3
+ endpoint: http://localhost:5000
4
+ props:
5
+ file: file
6
+ part_number: part_number
7
+ process_status:
8
+ path2: 0.processStatus[test=5..test
9
+ route: /process
10
+ data-items:
11
+ - file
12
+ - part_number
13
+ - process_status
@@ -0,0 +1,3 @@
1
+ version: 2
2
+ device: json-http
3
+ endpoint: http://localhost:5000
@@ -0,0 +1,13 @@
1
+ version: 2
2
+ device: json-http
3
+ endpoint: http://localhost:5000
4
+ props:
5
+ file: file
6
+ part_number: part_number
7
+ process_status:
8
+ path: test[machineId=test123].processStatus[test=5].test
9
+ route: /process
10
+ data-items:
11
+ - file
12
+ - part_number
13
+ - process_status
@@ -0,0 +1,46 @@
1
+ version: 2
2
+ device: labjack-t4
3
+ host: 192.168.1.100
4
+ mtconnect-port: 8001
5
+ variables:
6
+ var1:
7
+ - source: AIN0
8
+ - threshold: 5
9
+ var2:
10
+ - source: AIN0 + AIN1
11
+ - threshold: 5
12
+ var3:
13
+ - source: max(AIN0, AIN2)
14
+ - threshold: 5
15
+ var4:
16
+ - source: AIN0
17
+ - expression: this and (AIN3 > 2.5)
18
+ data1:
19
+ - source: FIO4
20
+ data2:
21
+ - state:
22
+ - ON: var2 and FIO5 > 4
23
+ - OFF: true
24
+ alarm-code:
25
+ - source: 100
26
+ alarm-message:
27
+ - state:
28
+ - TEST-MESSAGE: true
29
+ data-items:
30
+ - data1
31
+ - data2
32
+ conditions:
33
+ shorthand:
34
+ code: A${alarm-code}
35
+ message: ${alarm-message}
36
+ value:
37
+ WARNING: FIO5 < 3
38
+ system:
39
+ - code: A1
40
+ message: test alarm
41
+ value:
42
+ FAULT: FIO6 > 4
43
+ - code: B${alarm-code}
44
+ message: B ${alarm-message}
45
+ value:
46
+ FAULT: FIO6 < 2
@@ -0,0 +1,3 @@
1
+ version: 2
2
+ device: labjack-t4
3
+ host: 192.168.1.100
@@ -0,0 +1,41 @@
1
+ version: 2
2
+ device: labjack-t4
3
+ host: 192.168.1.100
4
+ mtconnect-port: 8001
5
+ variables:
6
+ var1:
7
+ - source: AIN0
8
+ - threshold: 5
9
+ var2:
10
+ - source: AIN0 + AIN1
11
+ - threshold: 5
12
+ var3:
13
+ - source: max(AIN0, AIN2)
14
+ - threshold: 5
15
+ var4:
16
+ - source: AIN0
17
+ - expression: this and (AIN3 > 2.5)
18
+ data1:
19
+ - source: FIO4
20
+ data2:
21
+ - state:
22
+ - ON: var2 and FIO5 > 4
23
+ - OFF: true
24
+ data-items:
25
+ - data1
26
+ - data2
27
+ conditions:
28
+ shorthand:
29
+ code: alarm0
30
+ message: heh
31
+ value:
32
+ WARNING: FIO5 < 3
33
+ system:
34
+ - code: alarm1
35
+ message: test alarm
36
+ value:
37
+ FAULT: FIO6 > 4
38
+ - code: alarm2
39
+ message: other alarm same pin
40
+ value:
41
+ FAULT: FIO6 < 2
@@ -0,0 +1,40 @@
1
+ version: 2
2
+ device: labjack-t4
3
+ host: 192.168.1.100
4
+ mtconnect-port: 8001
5
+ variables:
6
+ var1:
7
+ - source: pin-0
8
+ - threshold: 5
9
+ var2:
10
+ - source: pin-0 + pin-1
11
+ - threshold: 5
12
+ var3:
13
+ - source: max(pin-0, pin-2)
14
+ - threshold: 5
15
+ var4:
16
+ - source: pin-0
17
+ - expression: this and (pin-3 > 2.5)
18
+ data-items:
19
+ data1:
20
+ value: pin-4
21
+ data2:
22
+ value:
23
+ ON: var2 and pin-5 > 4
24
+ OFF: true
25
+ conditions:
26
+ shorthand:
27
+ code: alarm0
28
+ message: heh
29
+ value:
30
+ WARNING: pin-5 < 3
31
+ system:
32
+ - code: alarm1
33
+ message: test alarm
34
+ value:
35
+ FAULT: pin-6 > 4
36
+ - code: alarm2
37
+ message: other alarm same pin
38
+ value:
39
+ FAULT: pin-6 < 2
40
+