@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.
- package/.circleci/config.yml +141 -0
- package/.eslintrc.json +36 -0
- package/.gitattributes +12 -0
- package/CHANGELOG.md +544 -0
- package/README.md +2 -0
- package/index.js +17 -0
- package/lib/config/adapterConfig.js +535 -0
- package/lib/config/common/allowDenyList.js +58 -0
- package/lib/config/common/jsonPath.js +44 -0
- package/lib/config/common/labjackU3T4Common.js +227 -0
- package/lib/config/common/validations.js +142 -0
- package/lib/config/configError.js +32 -0
- package/lib/config/device/adam-6052Config.js +103 -0
- package/lib/config/device/brotherHTTPConfig.js +215 -0
- package/lib/config/device/ethernetIPConfig.js +191 -0
- package/lib/config/device/ifmIotConfig.js +245 -0
- package/lib/config/device/jsonHttpConfig.js +76 -0
- package/lib/config/device/labjackT4Config.js +39 -0
- package/lib/config/device/labjackT7Config.js +192 -0
- package/lib/config/device/labjackU3Config.js +32 -0
- package/lib/config/device/modbusTcpConfig.js +336 -0
- package/lib/config/device/mqttBaseConfig.js +70 -0
- package/lib/config/device/mqttConfig.js +113 -0
- package/lib/config/device/mqttLincolnConfig.js +62 -0
- package/lib/config/device/mtconnectAdapterConfig.js +42 -0
- package/lib/config/device/mtconnectBaseConfig.js +136 -0
- package/lib/config/device/mtconnectConfig.js +52 -0
- package/lib/config/device/mtconnectHaasConfig.js +15 -0
- package/lib/config/device/nullConfig.js +81 -0
- package/lib/config/device/opcuaConfig.js +205 -0
- package/lib/config/device/pcccConfig.js +88 -0
- package/lib/config/engineConfigV1.js +382 -0
- package/lib/config/engineConfigV2.js +106 -0
- package/lib/config/generator/counterGenConfig.js +15 -0
- package/lib/config/generator/cronGenConfig.js +33 -0
- package/lib/config/generator/dateTimeGenConfig.js +33 -0
- package/lib/config/index.js +339 -0
- package/lib/config/transformConfigUtil.js +296 -0
- package/lib/engine/dataOutput.js +357 -0
- package/lib/engine/deviceOutput.js +186 -0
- package/lib/engine/engineV1.js +480 -0
- package/lib/engine/engineV2.js +719 -0
- package/lib/engine/index.js +34 -0
- package/lib/engine/transformBuilderV1.js +111 -0
- package/lib/engine/transformBuilderV2.js +74 -0
- package/lib/expressionService.js +330 -0
- package/lib/math.js +142 -0
- package/lib/transform/accumulate.js +98 -0
- package/lib/transform/average.js +56 -0
- package/lib/transform/debounce.js +152 -0
- package/lib/transform/downsample.js +69 -0
- package/lib/transform/edge.js +34 -0
- package/lib/transform/expression.js +91 -0
- package/lib/transform/fallingEdge.js +70 -0
- package/lib/transform/fromBuffer.js +89 -0
- package/lib/transform/hash.js +41 -0
- package/lib/transform/ignoreValue.js +118 -0
- package/lib/transform/index.js +93 -0
- package/lib/transform/invert.js +25 -0
- package/lib/transform/latch.js +99 -0
- package/lib/transform/latchValue.js +115 -0
- package/lib/transform/logicAnd.js +67 -0
- package/lib/transform/logicOr.js +67 -0
- package/lib/transform/map.js +115 -0
- package/lib/transform/max.js +57 -0
- package/lib/transform/maxLength.js +39 -0
- package/lib/transform/min.js +57 -0
- package/lib/transform/minDelta.js +40 -0
- package/lib/transform/offDelay.js +89 -0
- package/lib/transform/onDelay.js +89 -0
- package/lib/transform/patternEscape.js +24 -0
- package/lib/transform/patternMatch.js +194 -0
- package/lib/transform/patternReplace.js +170 -0
- package/lib/transform/patternTest.js +85 -0
- package/lib/transform/rateOfChange.js +56 -0
- package/lib/transform/reject.js +115 -0
- package/lib/transform/resample.js +96 -0
- package/lib/transform/risingEdge.js +90 -0
- package/lib/transform/risingEdgeCounter.js +179 -0
- package/lib/transform/sampleInterval.js +12 -0
- package/lib/transform/source.js +116 -0
- package/lib/transform/state.js +201 -0
- package/lib/transform/threshold.js +52 -0
- package/lib/transform/toBuffer.js +159 -0
- package/lib/transform/toggle.js +118 -0
- package/lib/transform/transformState.js +193 -0
- package/lib/transform/trim.js +27 -0
- package/lib/transform/util/chainSource.js +96 -0
- package/lib/transform/util/ringBuffer.js +34 -0
- package/lib/transform/valueChange.js +34 -0
- package/lib/transform/valueDecrease.js +38 -0
- package/lib/transform/valueIncrease.js +38 -0
- package/lib/transform/valueIncreaseDiff.js +66 -0
- package/lib/transform/whenUnavailable.js +73 -0
- package/lib/transform/windowCount.js +86 -0
- package/lib/util/fileUtil.js +44 -0
- package/package.json +38 -0
- package/test/.eslintrc.json +15 -0
- package/test/chainedTransform.test.js +88 -0
- package/test/conditions.test.js +118 -0
- package/test/config/ab-pccc.test.js +41 -0
- package/test/config/adam-6052.test.js +16 -0
- package/test/config/adapter.test.js +109 -0
- package/test/config/brother-http.test.js +19 -0
- package/test/config/ethernet-ip.test.js +19 -0
- package/test/config/ifm-iot.test.js +20 -0
- package/test/config/json-http.test.js +47 -0
- package/test/config/labjack-t4.test.js +78 -0
- package/test/config/labjack-t7.test.js +18 -0
- package/test/config/labjack-u3.test.js +17 -0
- package/test/config/modbusTcp.test.js +87 -0
- package/test/config/mqtt.test.js +19 -0
- package/test/config/mqttLincoln.test.js +29 -0
- package/test/config/mtconnect.test.js +63 -0
- package/test/config/mtconnectAdapter.test.js +124 -0
- package/test/config/mtconnectHaas.test.js +15 -0
- package/test/config/null.test.js +16 -0
- package/test/config/opcua.test.js +97 -0
- package/test/config-tests.js +102 -0
- package/test/configFiles/conditions.yml +37 -0
- package/test/configFiles/data-items-legacy.yml +24 -0
- package/test/configFiles/data-items-shorthand.yml +14 -0
- package/test/configFiles/data-items.yml +12 -0
- package/test/configFiles/device/ab-pccc-default.yml +3 -0
- package/test/configFiles/device/ab-pccc-full.yml +13 -0
- package/test/configFiles/device/adam-6052-default.yml +2 -0
- package/test/configFiles/device/brother-http-default.yml +3 -0
- package/test/configFiles/device/ethernet-ip-default.yml +2 -0
- package/test/configFiles/device/ifm-iot-default.yml +2 -0
- package/test/configFiles/device/json-http-bad-prop.yml +13 -0
- package/test/configFiles/device/json-http-bad-prop2.yml +13 -0
- package/test/configFiles/device/json-http-default.yml +3 -0
- package/test/configFiles/device/json-http-std.yml +13 -0
- package/test/configFiles/device/labjack-t4-condition-exprs.yaml +46 -0
- package/test/configFiles/device/labjack-t4-default.yml +3 -0
- package/test/configFiles/device/labjack-t4-pins-alt.yaml +41 -0
- package/test/configFiles/device/labjack-t4-pins.yaml +40 -0
- package/test/configFiles/device/labjack-t4-v1.yaml +29 -0
- package/test/configFiles/device/labjack-t7-default.yml +2 -0
- package/test/configFiles/device/labjack-u3-default.yml +2 -0
- package/test/configFiles/device/modbus-partial.yml +4 -0
- package/test/configFiles/device/modbus-std-extended.yaml +23 -0
- package/test/configFiles/device/modbus-std.yaml +34 -0
- package/test/configFiles/device/modbus-tcp-default.yml +3 -0
- package/test/configFiles/device/mqtt-default.yml +2 -0
- package/test/configFiles/device/mqtt-lincoln-default.yml +3 -0
- package/test/configFiles/device/mqtt-lincoln-full.yml +7 -0
- package/test/configFiles/device/mtconnect-adapter-default.yml +3 -0
- package/test/configFiles/device/mtconnect-adapter-keys.yaml +18 -0
- package/test/configFiles/device/mtconnect-complex-keys.yaml +17 -0
- package/test/configFiles/device/mtconnect-default.yml +3 -0
- package/test/configFiles/device/mtconnect-duplicate-allow-keys.yaml +10 -0
- package/test/configFiles/device/mtconnect-duplicate-declare-keys.yaml +8 -0
- package/test/configFiles/device/mtconnect-duplicate-deny-keys.yaml +10 -0
- package/test/configFiles/device/mtconnect-haas-default.yml +3 -0
- package/test/configFiles/device/mtconnect-std.yaml +18 -0
- package/test/configFiles/device/null-default.yml +1 -0
- package/test/configFiles/device/opcua-bad-tag.yml +18 -0
- package/test/configFiles/device/opcua-bad-tag2.yml +18 -0
- package/test/configFiles/device/opcua-default.yml +3 -0
- package/test/configFiles/device/opcua-std.yml +18 -0
- package/test/configFiles/dump-test.yml +11 -0
- package/test/configFiles/expressionCond.yml +46 -0
- package/test/configFiles/min-config-t4.yaml +4 -0
- package/test/configFiles/min-config-u3.yaml +3 -0
- package/test/configFiles/missing-device.yaml +2 -0
- package/test/configFiles/parse-error1.yml +9 -0
- package/test/configFiles/parse-error2.yml +9 -0
- package/test/configFiles/repro/buffer-convert-repro.yml +15 -0
- package/test/configFiles/repro/chained-delay-timing-repro.yml +13 -0
- package/test/configFiles/repro/count-init-repro.yml +45 -0
- package/test/configFiles/repro/cycle-break-repro.yml +44 -0
- package/test/configFiles/repro/debounce-repro.yml +46 -0
- package/test/configFiles/repro/diff-count-repro.yml +34 -0
- package/test/configFiles/repro/engine-hang-repro.yml +9 -0
- package/test/configFiles/repro/latch-apm-repro.yml +26 -0
- package/test/configFiles/repro/lockout-count-repro.yml +33 -0
- package/test/configFiles/repro/program-extract-repro.yml +38 -0
- package/test/configFiles/repro/state-latch-repro.yml +47 -0
- package/test/configFiles/repro/ternary-repro.yml +26 -0
- package/test/configFiles/transform/debounce.yml +12 -0
- package/test/configFiles/transform/expression.yml +34 -0
- package/test/configFiles/transform/ignoreValue.yml +31 -0
- package/test/configFiles/transform/latch.yml +11 -0
- package/test/configFiles/transform/latchValue.yml +31 -0
- package/test/configFiles/transform/logicAnd.yml +14 -0
- package/test/configFiles/transform/logicOr.yml +14 -0
- package/test/configFiles/transform/map.yml +19 -0
- package/test/configFiles/transform/maxLength.yml +13 -0
- package/test/configFiles/transform/offDelay.yml +12 -0
- package/test/configFiles/transform/pattern-escape.yml +10 -0
- package/test/configFiles/transform/pattern-match.yml +57 -0
- package/test/configFiles/transform/pattern-replace.yml +34 -0
- package/test/configFiles/transform/pattern-test.yml +25 -0
- package/test/configFiles/transform/reject.yml +24 -0
- package/test/configFiles/transform/risingEdgeCounter.yml +36 -0
- package/test/configFiles/transform/source.yml +20 -0
- package/test/configFiles/transform/state.yml +56 -0
- package/test/configFiles/transform/toggle.yml +19 -0
- package/test/configFiles/transform/whenUnavailable.yml +19 -0
- package/test/dataFiles/noisy-pulse.txt +11330 -0
- package/test/dataItems.test.js +140 -0
- package/test/engine-v1-tests.js +418 -0
- package/test/engine-v2-tests.js +284 -0
- package/test/expression-tests.js +171 -0
- package/test/expressionService.test.js +154 -0
- package/test/expressionServiceCondition.test.js +130 -0
- package/test/repro/buffer-convert-repro.test.js +38 -0
- package/test/repro/chained-delay-timing-repro.test.js +34 -0
- package/test/repro/count-init-repro.test.js +46 -0
- package/test/repro/cylce-break-repro.test.js +57 -0
- package/test/repro/debounce-repro.test.js +65 -0
- package/test/repro/diff-count-repro.test.js +79 -0
- package/test/repro/engine-hang-repro.test.js +38 -0
- package/test/repro/latch-apm-repro.test.js +119 -0
- package/test/repro/lockout-count-repro.test.js +84 -0
- package/test/repro/program-extract-repro.test.js +40 -0
- package/test/repro/state-latch-repro.test.js +63 -0
- package/test/repro/ternary-repro.test.js +43 -0
- package/test/transform/accumulte.test.js +18 -0
- package/test/transform/average.test.js +22 -0
- package/test/transform/debounce.test.js +70 -0
- package/test/transform/downsample.test.js +30 -0
- package/test/transform/edge.test.js +27 -0
- package/test/transform/expression.test.js +189 -0
- package/test/transform/fallingEdge.test.js +59 -0
- package/test/transform/fromBuffer.test.js +60 -0
- package/test/transform/hash.test.js +34 -0
- package/test/transform/ignoreValue.test.js +123 -0
- package/test/transform/invert.test.js +26 -0
- package/test/transform/latch.test.js +33 -0
- package/test/transform/latchValue.test.js +126 -0
- package/test/transform/logicAnd.test.js +80 -0
- package/test/transform/logicOr.test.js +80 -0
- package/test/transform/map.test.js +42 -0
- package/test/transform/max.test.js +30 -0
- package/test/transform/maxLength.test.js +32 -0
- package/test/transform/min.test.js +30 -0
- package/test/transform/minDelta.test.js +14 -0
- package/test/transform/offDelay.test.js +123 -0
- package/test/transform/onDelay.test.js +105 -0
- package/test/transform/patternEscape.test.js +18 -0
- package/test/transform/patternMatch.test.js +177 -0
- package/test/transform/patternReplace.test.js +95 -0
- package/test/transform/patternTest.test.js +105 -0
- package/test/transform/rateOfChange.test.js +34 -0
- package/test/transform/reject.test.js +56 -0
- package/test/transform/resample.test.js +193 -0
- package/test/transform/risingEdge.test.js +60 -0
- package/test/transform/risingEdgeCounter.test.js +227 -0
- package/test/transform/sampleInterval.test.js +22 -0
- package/test/transform/source.test.js +137 -0
- package/test/transform/state.test.js +248 -0
- package/test/transform/threshold.test.js +78 -0
- package/test/transform/toBuffer.test.js +60 -0
- package/test/transform/toggle.test.js +92 -0
- package/test/transform/trim.test.js +30 -0
- package/test/transform/valueChange.test.js +14 -0
- package/test/transform/valueDecrease.test.js +32 -0
- package/test/transform/valueIncrease.test.js +32 -0
- package/test/transform/valueIncreaseDiff.test.js +32 -0
- package/test/transform/whenUnavailable.test.js +93 -0
- package/test/transform/windowCount.test.js +26 -0
- package/test/util/testUtils.js +405 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const ConfigError = require('../configError');
|
|
5
|
+
const { checkJsonPropPath } = require('../common/jsonPath');
|
|
6
|
+
|
|
7
|
+
class JsonHttpConfig {
|
|
8
|
+
constructor(expressionService) {
|
|
9
|
+
this.expressionService = expressionService;
|
|
10
|
+
|
|
11
|
+
_.each(this.getIdentifiers(expressionService.config), (name) => this.expressionService.addName(name));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getIdentifiers(config = {}) {
|
|
15
|
+
return _.map(_.keys(config.props), (name) => {
|
|
16
|
+
return {
|
|
17
|
+
name,
|
|
18
|
+
channel: 'device',
|
|
19
|
+
defaultValue: 0,
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
device() {
|
|
25
|
+
return 'json-http';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
parse(config = {}) {
|
|
29
|
+
if (config.device !== this.device()) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
this.insecure = config.insecure;
|
|
34
|
+
this.scanInterval = this.checkScanInterval(config);
|
|
35
|
+
this.endpoint = config.endpoint;
|
|
36
|
+
this.props = this.loadProps(config);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
loadProps(config) {
|
|
40
|
+
const props = _.mapValues(config.props, (value) => {
|
|
41
|
+
if (_.isObject(value)) {
|
|
42
|
+
return {
|
|
43
|
+
path: value.path,
|
|
44
|
+
route: value.route || config.route,
|
|
45
|
+
};
|
|
46
|
+
} else {
|
|
47
|
+
return {
|
|
48
|
+
path: value,
|
|
49
|
+
route: config.route,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
_.each(props, (prop, key) => checkJsonPropPath(prop.path, key));
|
|
56
|
+
} catch (error) {
|
|
57
|
+
if (error instanceof ConfigError) {
|
|
58
|
+
error.atSection('props');
|
|
59
|
+
}
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return props;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
checkScanInterval(config) {
|
|
67
|
+
const scanIntvl = +(config['scan-interval'] || 1.0);
|
|
68
|
+
if (scanIntvl < 1) {
|
|
69
|
+
throw new ConfigError('scan-interval must be >= 1').atAttribute('scan-interval');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return Math.ceil(scanIntvl * 1000);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
module.exports = JsonHttpConfig;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const { scanInterval, deviceIdentifiers, loadPins } = require('../common/labjackU3T4Common');
|
|
5
|
+
const ConfigError = require('../configError');
|
|
6
|
+
|
|
7
|
+
class LabjackT4Config {
|
|
8
|
+
constructor(expressionService) {
|
|
9
|
+
this.expressionService = expressionService;
|
|
10
|
+
|
|
11
|
+
_.each(this.getIdentifiers(), name => this.expressionService.addName(name));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getIdentifiers() {
|
|
15
|
+
return deviceIdentifiers();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
device() {
|
|
19
|
+
return 'labjack-t4';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
parse(config = {}) {
|
|
23
|
+
if (config.device !== this.device()) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
this.scanInterval = scanInterval(config);
|
|
28
|
+
|
|
29
|
+
if (!config.host) {
|
|
30
|
+
throw new ConfigError('No host defined');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
this.host = config.host;
|
|
34
|
+
|
|
35
|
+
this.pins = loadPins('T4', config);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = LabjackT4Config;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const ConfigError = require('../configError');
|
|
5
|
+
|
|
6
|
+
const dacPins = _.times(2, i => `DAC${i}`);
|
|
7
|
+
const analogPins = _.times(14, i => `AIN${i}`);
|
|
8
|
+
const digitalPins = [
|
|
9
|
+
..._.times(8, i => `FIO${i}`),
|
|
10
|
+
..._.times(8, i => `EIO${i}`),
|
|
11
|
+
..._.times(4, i => `CIO${i}`),
|
|
12
|
+
..._.times(3, i => `MIO${i}`),
|
|
13
|
+
];
|
|
14
|
+
const allPins = [
|
|
15
|
+
...dacPins,
|
|
16
|
+
...analogPins,
|
|
17
|
+
...digitalPins,
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
class LabjackT7Config {
|
|
21
|
+
constructor(expressionService) {
|
|
22
|
+
this.expressionService = expressionService;
|
|
23
|
+
|
|
24
|
+
_.each(this.getIdentifiers(), name => this.expressionService.addName(name));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
getIdentifiers() {
|
|
28
|
+
return _.map([...analogPins, ...digitalPins], (name) => {
|
|
29
|
+
return {
|
|
30
|
+
name,
|
|
31
|
+
channel: 'device',
|
|
32
|
+
defaultValue: 0,
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
parse(config = {}) {
|
|
38
|
+
if (config.device !== this.device()) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const scanIntervalRequest = config['scan-interval'] || 0.002;
|
|
43
|
+
const scanInterval4MHz = Math.floor(scanIntervalRequest * 4000000);
|
|
44
|
+
if (scanInterval4MHz <= 0) {
|
|
45
|
+
throw new ConfigError('scan-interval must be > 0').atAttribute('scan-interval');
|
|
46
|
+
}
|
|
47
|
+
if (scanInterval4MHz > 65535) {
|
|
48
|
+
throw new ConfigError('scan-interval must be <= 0.016').atAttribute('scan-interval');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.scanInterval = scanInterval4MHz / 4000000;
|
|
52
|
+
|
|
53
|
+
if (!config.host) {
|
|
54
|
+
throw new ConfigError('No host defined');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this.host = config.host;
|
|
58
|
+
|
|
59
|
+
this.pins = this.loadPins(config);
|
|
60
|
+
|
|
61
|
+
// Fill out any pins not explicitly defined with default configs
|
|
62
|
+
_.each(analogPins, (name) => {
|
|
63
|
+
if (!this.pins[name]) {
|
|
64
|
+
this.pins[name] = this.makeAnalogPin({ name });
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
_.each(digitalPins, (name) => {
|
|
69
|
+
if (!this.pins[name]) {
|
|
70
|
+
this.pins[name] = this.makeDigitalPin({ name });
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
_.each(dacPins, (name) => {
|
|
75
|
+
if (!this.pins[name]) {
|
|
76
|
+
this.pins[name] = this.makeDacPin({ name });
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
device() {
|
|
82
|
+
return 'labjack-t7';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
loadPins(config = {}) {
|
|
86
|
+
return _.mapValues(config.pins, (defn, name) => {
|
|
87
|
+
if (!defn) {
|
|
88
|
+
defn = { };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!_.includes(allPins, name)) {
|
|
92
|
+
throw new ConfigError(`${name} is not a valid T7 pin`).atPath(`pins.${name}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
if (defn.mode) {
|
|
97
|
+
throw new ConfigError('Mode cannot be set on T7 analog or digital pins').atAttribute('mode');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const direction = this.checkPinDirection(defn, name);
|
|
101
|
+
const range = this.checkPinRange(defn, name);
|
|
102
|
+
const dacValue = this.checkPinDacValue(defn, name);
|
|
103
|
+
|
|
104
|
+
if (_.includes(analogPins, name)) {
|
|
105
|
+
return this.makeAnalogPin({ name, range });
|
|
106
|
+
} else if (_.includes(digitalPins, name)) {
|
|
107
|
+
return this.makeDigitalPin({ name, direction });
|
|
108
|
+
} else if (_.includes(dacPins, name)) {
|
|
109
|
+
return this.makeDacPin({ name, value: dacValue });
|
|
110
|
+
}
|
|
111
|
+
throw new ConfigError(`${name} is an unknown pin type`).atPath(`pins.${name}`);
|
|
112
|
+
} catch (err) {
|
|
113
|
+
if (err instanceof ConfigError) {
|
|
114
|
+
err.atSection(`pins.${name}`);
|
|
115
|
+
}
|
|
116
|
+
throw err;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
makeAnalogPin({ name, range = 10 }) {
|
|
122
|
+
return {
|
|
123
|
+
name,
|
|
124
|
+
mode: 'analog',
|
|
125
|
+
direction: 'input',
|
|
126
|
+
range,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
makeDigitalPin({ name, direction = 'input' }) {
|
|
131
|
+
return {
|
|
132
|
+
name,
|
|
133
|
+
mode: 'digital',
|
|
134
|
+
direction,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
makeDacPin({ name, value = 0 }) {
|
|
139
|
+
return {
|
|
140
|
+
name,
|
|
141
|
+
mode: 'dac',
|
|
142
|
+
value,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
checkPinDirection(defn, name) {
|
|
147
|
+
if (!_.includes(digitalPins, name)) {
|
|
148
|
+
if (!_.isUndefined(defn.direction)) {
|
|
149
|
+
throw new ConfigError('Direction can only be set on digital pins').atAttribute('direction');
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const direction = defn.direction || 'input';
|
|
155
|
+
if (!_.includes(['input', 'output'], direction)) {
|
|
156
|
+
throw new ConfigError('Direction must be one of [input, output]').atAttribute('direction');
|
|
157
|
+
}
|
|
158
|
+
return direction;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
checkPinRange(defn, name) {
|
|
162
|
+
if (!_.includes(analogPins, name)) {
|
|
163
|
+
if (!_.isUndefined(defn.range)) {
|
|
164
|
+
throw new ConfigError('Range can only be set on analog pins').atAttribute('range');
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const range = defn.range || 10;
|
|
170
|
+
if (!_.isNumber(range) || range <= 0) {
|
|
171
|
+
throw new ConfigError('Range must be > 0').atAttribute('range');
|
|
172
|
+
}
|
|
173
|
+
return range;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
checkPinDacValue(defn, name) {
|
|
177
|
+
if (!_.includes(dacPins, name)) {
|
|
178
|
+
if (!_.isUndefined(defn.value)) {
|
|
179
|
+
throw new ConfigError('Output value can only be set on DAC pins').atAttribute('value');
|
|
180
|
+
}
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const value = defn.value || 0;
|
|
185
|
+
if (!_.isNumber(value) || value < 0 || value > 5) {
|
|
186
|
+
throw new ConfigError('Output value must be between 0 and 5 (volts)').atAttribute('value');
|
|
187
|
+
}
|
|
188
|
+
return value;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
module.exports = LabjackT7Config;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const { scanInterval, deviceIdentifiers, loadPins } = require('../common/labjackU3T4Common');
|
|
5
|
+
|
|
6
|
+
class LabjackU3Config {
|
|
7
|
+
constructor(expressionService) {
|
|
8
|
+
this.expressionService = expressionService;
|
|
9
|
+
|
|
10
|
+
_.each(this.getIdentifiers(), name => this.expressionService.addName(name));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
getIdentifiers() {
|
|
14
|
+
return deviceIdentifiers();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
device() {
|
|
18
|
+
return 'labjack-u3';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
parse(config = {}) {
|
|
22
|
+
if (config.device !== this.device()) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
this.scanInterval = scanInterval(config);
|
|
27
|
+
|
|
28
|
+
this.pins = loadPins('U3-HV', config);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = LabjackU3Config;
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const ConfigError = require('../configError');
|
|
5
|
+
|
|
6
|
+
class ModbusTcpConfig {
|
|
7
|
+
constructor(expressionService) {
|
|
8
|
+
this.expressionService = expressionService;
|
|
9
|
+
|
|
10
|
+
_.each(this.getIdentifiers(expressionService.config), name => this.expressionService.addName(name));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
getIdentifiers(config = {}) {
|
|
14
|
+
const coils = _.map(config.coils, (coil, name) => {
|
|
15
|
+
return {
|
|
16
|
+
name,
|
|
17
|
+
channel: 'device',
|
|
18
|
+
defaultValue: false,
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const registers = _.map(config.registers, (register, name) => {
|
|
23
|
+
let defaultValue = 0;
|
|
24
|
+
if (register.type === 'string') {
|
|
25
|
+
defaultValue = '';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
name,
|
|
30
|
+
channel: 'device',
|
|
31
|
+
defaultValue,
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return [...coils, ...registers];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
parse(config = {}) {
|
|
39
|
+
if (!config.host) {
|
|
40
|
+
throw new ConfigError('No host defined');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
this.host = config.host;
|
|
44
|
+
this.port = config.port || 502;
|
|
45
|
+
this.unitId = config['unit-id'] || 0;
|
|
46
|
+
|
|
47
|
+
this.byteOrder = this.checkByteOrder(config);
|
|
48
|
+
this.wordOrder = this.checkWordOrder(config);
|
|
49
|
+
this.addressSpace = this.checkAddressSpace(config);
|
|
50
|
+
this.stringEncoding = this.checkStringEncoding(config);
|
|
51
|
+
|
|
52
|
+
this.scanInterval = this.checkScanInterval(config);
|
|
53
|
+
|
|
54
|
+
this.coils = this.loadCoils(config.coils);
|
|
55
|
+
this.registers = this.loadRegisters(config.registers);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
loadCoils(coils = {}) {
|
|
59
|
+
return _(coils).map((defn, name) => {
|
|
60
|
+
try {
|
|
61
|
+
const shorthand = !_.isObject(defn);
|
|
62
|
+
if (shorthand) {
|
|
63
|
+
defn = { address: defn };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const func = this.checkCoilFunction(defn, shorthand);
|
|
67
|
+
const address = this.checkCoilAddress(defn, shorthand);
|
|
68
|
+
|
|
69
|
+
const scanInterval = defn['scan-interval'] ? this.checkScanInterval(defn) : undefined;
|
|
70
|
+
|
|
71
|
+
return { name, func, address, scanInterval };
|
|
72
|
+
} catch (error) {
|
|
73
|
+
if (error instanceof ConfigError) {
|
|
74
|
+
error.atSection(`coils.${name}`);
|
|
75
|
+
}
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
}).keyBy('name').value();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
loadRegisters(registers = {}) {
|
|
82
|
+
return _(registers).map((defn, name) => {
|
|
83
|
+
try {
|
|
84
|
+
const func = this.checkRegisterFunction(defn);
|
|
85
|
+
const address = this.checkRegisterAddress(defn);
|
|
86
|
+
const type = this.checkType(defn);
|
|
87
|
+
const size = this.checkSize(defn);
|
|
88
|
+
|
|
89
|
+
const scanInterval = defn['scan-interval'] ? this.checkScanInterval(defn) : undefined;
|
|
90
|
+
|
|
91
|
+
return { name, func, address, type, size, scanInterval };
|
|
92
|
+
} catch (error) {
|
|
93
|
+
if (error instanceof ConfigError) {
|
|
94
|
+
error.atSection(`registers.${name}`);
|
|
95
|
+
}
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
}).keyBy('name').value();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
checkScanInterval(defn) {
|
|
102
|
+
const scanInterval = +(defn['scan-interval'] || 1.0);
|
|
103
|
+
if (scanInterval <= 0) {
|
|
104
|
+
throw new ConfigError('scan-interval must be > 0').atAttribute('scan-interval');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return Math.ceil(scanInterval * 1000);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
checkCoilFunction(defn, shorthand = false) {
|
|
111
|
+
let func = defn.func || this.addressSpace;
|
|
112
|
+
let address = defn.address || 0;
|
|
113
|
+
if (_.isString(address)) {
|
|
114
|
+
address = parseInt(address, 10);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (func === 'mixed') {
|
|
118
|
+
if (address > 0 && address < 10000) {
|
|
119
|
+
func = 1;
|
|
120
|
+
} else if (address > 10000 && address < 20000) {
|
|
121
|
+
func = 2;
|
|
122
|
+
} else {
|
|
123
|
+
const err = new ConfigError('Address out of range for mixed coil address space');
|
|
124
|
+
if (!shorthand) {
|
|
125
|
+
err.atAttribute('address');
|
|
126
|
+
}
|
|
127
|
+
throw err;
|
|
128
|
+
}
|
|
129
|
+
} else if (func === 'extended') {
|
|
130
|
+
if (address > 0 && address < 100000) {
|
|
131
|
+
func = 1;
|
|
132
|
+
} else if (address > 100000 && address < 200000) {
|
|
133
|
+
func = 2;
|
|
134
|
+
} else {
|
|
135
|
+
const err = new ConfigError('Address out of range for extended coil address space');
|
|
136
|
+
if (!shorthand) {
|
|
137
|
+
err.atAttribute('address');
|
|
138
|
+
}
|
|
139
|
+
throw err;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (!_.includes([1, 2], func)) {
|
|
144
|
+
const err = new ConfigError('Valid functions are 1 or 2');
|
|
145
|
+
if (!shorthand) {
|
|
146
|
+
err.atAttribute('function');
|
|
147
|
+
}
|
|
148
|
+
throw err;
|
|
149
|
+
}
|
|
150
|
+
return func;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
checkRegisterFunction(defn) {
|
|
154
|
+
let func = defn.func || this.addressSpace;
|
|
155
|
+
let address = defn.address || 0;
|
|
156
|
+
if (_.isString(address)) {
|
|
157
|
+
address = parseInt(address, 10);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (func === 'mixed') {
|
|
161
|
+
if (address > 30000 && address < 40000) {
|
|
162
|
+
func = 4;
|
|
163
|
+
} else if (address > 40000 && address < 50000) {
|
|
164
|
+
func = 3;
|
|
165
|
+
} else {
|
|
166
|
+
throw new ConfigError('Address out of range for mixed register address space').atAttribute('address');
|
|
167
|
+
}
|
|
168
|
+
} else if (func === 'extended') {
|
|
169
|
+
if (address > 300000 && address < 400000) {
|
|
170
|
+
func = 4;
|
|
171
|
+
} else if (address > 400000 && address < 500000) {
|
|
172
|
+
func = 3;
|
|
173
|
+
} else {
|
|
174
|
+
throw new ConfigError('Address out of range for extended register address space').atAttribute('address');
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (!_.includes([3, 4], func)) {
|
|
179
|
+
throw new ConfigError('Valid functions are 3 or 4').atAttribute('function');
|
|
180
|
+
}
|
|
181
|
+
return func;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
checkCoilAddress(defn, shorthand = false) {
|
|
185
|
+
const func = defn.func || this.addressSpace;
|
|
186
|
+
let address = defn.address;
|
|
187
|
+
if (_.isString(address)) {
|
|
188
|
+
address = parseInt(address, 10);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (func === 'mixed') {
|
|
192
|
+
if (address > 0 && address < 10000) {
|
|
193
|
+
address -= 1;
|
|
194
|
+
} else if (address > 10000 && address < 20000) {
|
|
195
|
+
address -= 10001;
|
|
196
|
+
} else {
|
|
197
|
+
const err = new ConfigError('Address out of range for mixed coil address space');
|
|
198
|
+
if (!shorthand) {
|
|
199
|
+
err.atAttribute('address');
|
|
200
|
+
}
|
|
201
|
+
throw err;
|
|
202
|
+
}
|
|
203
|
+
} else if (func === 'extended') {
|
|
204
|
+
if (address > 0 && address < 100000) {
|
|
205
|
+
address -= 1;
|
|
206
|
+
} else if (address > 100000 && address < 200000) {
|
|
207
|
+
address -= 100001;
|
|
208
|
+
} else {
|
|
209
|
+
const err = new ConfigError('Address out of range for extended coil address space');
|
|
210
|
+
if (!shorthand) {
|
|
211
|
+
err.atAttribute('address');
|
|
212
|
+
}
|
|
213
|
+
throw err;
|
|
214
|
+
}
|
|
215
|
+
} else if (func >= 1 && func <= 2) {
|
|
216
|
+
if (address === undefined || address < 0 || address >= 65536) {
|
|
217
|
+
const err = new ConfigError('Address must be in range [0, 65535]');
|
|
218
|
+
if (!shorthand) {
|
|
219
|
+
err.atAttribute('address');
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return address;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
checkRegisterAddress(defn) {
|
|
227
|
+
const func = defn.func || this.addressSpace;
|
|
228
|
+
let address = defn.address;
|
|
229
|
+
if (_.isString(address)) {
|
|
230
|
+
address = parseInt(address, 10);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (func === 'mixed') {
|
|
234
|
+
if (address > 30000 && address < 40000) {
|
|
235
|
+
address -= 30001;
|
|
236
|
+
} else if (address > 40000 && address < 50000) {
|
|
237
|
+
address -= 40001;
|
|
238
|
+
} else {
|
|
239
|
+
throw new ConfigError('Address out of range for mixed register address space').atAttribute('address');
|
|
240
|
+
}
|
|
241
|
+
} else if (func === 'extended') {
|
|
242
|
+
if (address > 300000 && address < 400000) {
|
|
243
|
+
address -= 300001;
|
|
244
|
+
} else if (address > 400000 && address < 500000) {
|
|
245
|
+
address -= 400001;
|
|
246
|
+
} else {
|
|
247
|
+
throw new ConfigError('Address out of range for extended register address space').atAttribute('address');
|
|
248
|
+
}
|
|
249
|
+
} else if (func >= 3 && func <= 4) {
|
|
250
|
+
if (address === undefined || address < 0 || address >= 65536) {
|
|
251
|
+
throw new ConfigError('Address must be in range [0, 65535]').atAttribute('address');
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return address;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
checkType(defn) {
|
|
258
|
+
const type = defn.type;
|
|
259
|
+
if (!_.includes(['int16', 'uint16', 'int32', 'uint32', 'float32', 'string'], type)) {
|
|
260
|
+
throw new ConfigError('Type must be one of [int16, uint16, int32, uint32, float32, string]').atAttribute('type');
|
|
261
|
+
}
|
|
262
|
+
return type;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
checkStringEncoding(defn) {
|
|
266
|
+
const encoding = defn['string-encoding'] || 'ascii';
|
|
267
|
+
if (!_.includes(['ascii', 'utf8', 'ucs2', 'utf16le'], encoding)) {
|
|
268
|
+
throw new ConfigError('Encoding must be one of [ascii, utf8, ucs2, utf16le]').atAttribute('string-encoding');
|
|
269
|
+
}
|
|
270
|
+
return encoding;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
checkSize(defn) {
|
|
274
|
+
const type = defn.type;
|
|
275
|
+
if (type === 'int16' || type === 'uint16') {
|
|
276
|
+
return 1;
|
|
277
|
+
} else if (type === 'int32' || type === 'uint32' || type === 'float32') {
|
|
278
|
+
return 2;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const size = defn.size;
|
|
282
|
+
if (!size) {
|
|
283
|
+
throw new ConfigError('Size must be specified for string types').atAttribute('size');
|
|
284
|
+
}
|
|
285
|
+
return Math.floor((size + 1) / 2);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
checkByteOrder(defn) {
|
|
289
|
+
const order = defn['byte-order'] || 'big';
|
|
290
|
+
if (!_.includes(['big', 'little'], order)) {
|
|
291
|
+
throw new ConfigError('Valid byte-order values are big and little').atAttribute('byte-order');
|
|
292
|
+
}
|
|
293
|
+
return order;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
checkWordOrder(defn) {
|
|
297
|
+
const order = defn['word-order'] || 'big';
|
|
298
|
+
if (!_.includes(['big', 'little'], order)) {
|
|
299
|
+
throw new ConfigError('Valid word-order values are big and little').atAttribute('word-order');
|
|
300
|
+
}
|
|
301
|
+
return order;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
checkAddressSpace(defn) {
|
|
305
|
+
let addressSpace = defn['address-space'];
|
|
306
|
+
if (!addressSpace) {
|
|
307
|
+
if (this.hasExtendedAddressinging(defn.coils) || this.hasExtendedAddressinging(defn.registers)) {
|
|
308
|
+
addressSpace = 'extended';
|
|
309
|
+
} else {
|
|
310
|
+
addressSpace = 'mixed';
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (!_.includes(['mixed', 'extended', 1, 2, 3, 4], addressSpace)) {
|
|
315
|
+
throw new ConfigError('Valid address spaces are 1, 2, 3, 4, mixed, or extended').atAttribute('address-space');
|
|
316
|
+
}
|
|
317
|
+
return addressSpace;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
hasExtendedAddressinging(block) {
|
|
321
|
+
let extended = false;
|
|
322
|
+
_.each(block, (item) => {
|
|
323
|
+
if (_.isString(item.address)) {
|
|
324
|
+
if (item.address.lenth === 6) {
|
|
325
|
+
extended = true;
|
|
326
|
+
}
|
|
327
|
+
} else if (item.address >= 50000) {
|
|
328
|
+
extended = true;
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
return extended;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
module.exports = ModbusTcpConfig;
|