node-red-contrib-i3x 0.0.1

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.
@@ -0,0 +1,72 @@
1
+ <script type="text/html" data-template-name="i3x-write">
2
+ <div class="form-row">
3
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
4
+ <input type="text" id="node-input-name" placeholder="Name">
5
+ </div>
6
+ <div class="form-row">
7
+ <label for="node-input-server"><i class="fa fa-server"></i> Server</label>
8
+ <input type="text" id="node-input-server">
9
+ </div>
10
+ <div class="form-row">
11
+ <label for="node-input-writeTarget"><i class="fa fa-bullseye"></i> Target</label>
12
+ <select id="node-input-writeTarget">
13
+ <option value="value">Current Value</option>
14
+ <option value="history">Historical Data</option>
15
+ </select>
16
+ </div>
17
+ <div class="form-row">
18
+ <label for="node-input-elementId"><i class="fa fa-crosshairs"></i> Element ID</label>
19
+ <input type="text" id="node-input-elementId" placeholder="target element ID">
20
+ </div>
21
+ </script>
22
+
23
+ <script type="text/html" data-help-name="i3x-write">
24
+ <p>Writes a current value or historical data to an i3X object.</p>
25
+
26
+ <h3>Inputs</h3>
27
+ <dl class="message-properties">
28
+ <dt>payload <span class="property-type">any</span></dt>
29
+ <dd>The value to write. Format depends on the element type schema.</dd>
30
+ <dt class="optional">elementId <span class="property-type">string</span></dt>
31
+ <dd>Target element ID. Overrides the configured value. Also accepts <code>msg.nodeId</code>.</dd>
32
+ <dt class="optional">writeTarget <span class="property-type">string</span></dt>
33
+ <dd><code>"value"</code> (default) or <code>"history"</code>. Overrides the configured target.</dd>
34
+ </dl>
35
+
36
+ <h3>Outputs</h3>
37
+ <dl class="message-properties">
38
+ <dt>payload <span class="property-type">object</span></dt>
39
+ <dd>Write confirmation response from the API.</dd>
40
+ <dt>elementId <span class="property-type">string</span></dt>
41
+ <dd>The element ID that was written to.</dd>
42
+ </dl>
43
+
44
+ <h3>Details</h3>
45
+ <p>When <b>Target</b> is set to <i>Current Value</i>, uses <code>PUT /objects/{elementId}/value</code>
46
+ to update the current value of the object.</p>
47
+ <p>When <b>Target</b> is set to <i>Historical Data</i>, uses <code>PUT /objects/{elementId}/history</code>
48
+ to write historical time-series records.</p>
49
+ <p>The payload format must match the element's type schema (e.g. a plain number for
50
+ <code>measurement-value-type</code>, or a state object for <code>state-type</code>).</p>
51
+ </script>
52
+
53
+ <script type="text/javascript">
54
+ RED.nodes.registerType("i3x-write", {
55
+ category: "i3x",
56
+ color: "#5DB87C",
57
+ defaults: {
58
+ name: { value: "" },
59
+ server: { value: "", type: "i3x-server", required: true },
60
+ writeTarget: { value: "value" },
61
+ elementId: { value: "" },
62
+ },
63
+ inputs: 1,
64
+ outputs: 1,
65
+ icon: "i3x-icon.svg",
66
+ paletteLabel: "i3x write",
67
+ label: function () {
68
+ return this.name || this.elementId || "i3x write";
69
+ },
70
+ align: "right",
71
+ });
72
+ </script>
@@ -0,0 +1,56 @@
1
+ /**
2
+ * i3x-write – Write a value or historical data to an i3X object.
3
+ */
4
+ "use strict";
5
+
6
+ const { bindServer, safeSend } = require("../lib/node-utils");
7
+
8
+ module.exports = function (RED) {
9
+ function I3XWriteNode(config) {
10
+ RED.nodes.createNode(this, config);
11
+ const node = this;
12
+
13
+ node.elementId = config.elementId || "";
14
+ node.writeTarget = config.writeTarget || "value";
15
+
16
+ if (!bindServer(node, RED, config.server)) return;
17
+
18
+ node.on("input", async function (msg, send, done) {
19
+ send = safeSend(node, send);
20
+ const client = node.server.client;
21
+
22
+ const elementId = msg.elementId || msg.nodeId || node.elementId;
23
+ if (!elementId) {
24
+ const err = new Error("elementId is required");
25
+ if (done) done(err); else node.error(err, msg);
26
+ return;
27
+ }
28
+
29
+ const value = msg.payload;
30
+ if (value === undefined) {
31
+ const err = new Error("msg.payload (value to write) is required");
32
+ if (done) done(err); else node.error(err, msg);
33
+ return;
34
+ }
35
+
36
+ const target = msg.writeTarget || node.writeTarget;
37
+ node.status({ fill: "blue", shape: "dot", text: "writing..." });
38
+
39
+ try {
40
+ const result = target === "history"
41
+ ? await client.writeHistory(elementId, value)
42
+ : await client.writeValue(elementId, value);
43
+ msg.payload = result;
44
+ msg.elementId = elementId;
45
+ node.status({ fill: "green", shape: "dot", text: "ok" });
46
+ send(msg);
47
+ if (done) done();
48
+ } catch (err) {
49
+ node.status({ fill: "red", shape: "ring", text: err.message.substring(0, 32) });
50
+ if (done) done(err); else node.error(err, msg);
51
+ }
52
+ });
53
+ }
54
+
55
+ RED.nodes.registerType("i3x-write", I3XWriteNode);
56
+ };
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" width="40" height="40">
2
+ <rect width="40" height="40" rx="4" fill="#2E8B57"/>
3
+ <text x="20" y="16" text-anchor="middle" font-family="Arial, sans-serif" font-size="10" font-weight="bold" fill="white">i3X</text>
4
+ <line x1="8" y1="22" x2="32" y2="22" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
5
+ <circle cx="12" cy="30" r="3" fill="none" stroke="white" stroke-width="1.5"/>
6
+ <circle cx="20" cy="30" r="3" fill="none" stroke="white" stroke-width="1.5"/>
7
+ <circle cx="28" cy="30" r="3" fill="none" stroke="white" stroke-width="1.5"/>
8
+ <line x1="12" y1="27" x2="12" y2="22" stroke="white" stroke-width="1.5"/>
9
+ <line x1="20" y1="27" x2="20" y2="22" stroke="white" stroke-width="1.5"/>
10
+ <line x1="28" y1="27" x2="28" y2="22" stroke="white" stroke-width="1.5"/>
11
+ </svg>
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "node-red-contrib-i3x",
3
+ "version": "0.0.1",
4
+ "description": "Node-RED nodes for the i3X (Industrial Information Interoperability eXchange) API by CESMII",
5
+ "keywords": [
6
+ "node-red",
7
+ "i3x",
8
+ "cesmii",
9
+ "industrial",
10
+ "manufacturing",
11
+ "iiot",
12
+ "historian",
13
+ "mes",
14
+ "mom",
15
+ "opc-ua",
16
+ "smart-manufacturing"
17
+ ],
18
+ "license": "MIT",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/cesmii/node-red-contrib-i3x"
22
+ },
23
+ "scripts": {
24
+ "test": "mocha --exit --timeout 15000 'test/**/*_spec.js'",
25
+ "test:unit": "mocha --exit --timeout 10000 'test/unit/**/*_spec.js'",
26
+ "test:integration": "mocha --exit --timeout 30000 'test/integration/**/*_spec.js'",
27
+ "test:docker": "docker compose run --rm test"
28
+ },
29
+ "dependencies": {
30
+ "axios": "^1.7.0"
31
+ },
32
+ "devDependencies": {
33
+ "mocha": "^10.0.0",
34
+ "chai": "^4.0.0",
35
+ "sinon": "^17.0.0",
36
+ "nock": "^13.0.0",
37
+ "node-red": "^3.0.0",
38
+ "node-red-node-test-helper": "^0.3.0"
39
+ },
40
+ "node-red": {
41
+ "version": ">=2.0.0",
42
+ "nodes": {
43
+ "i3x-server": "nodes/i3x-server.js",
44
+ "i3x-browse": "nodes/i3x-browse.js",
45
+ "i3x-read": "nodes/i3x-read.js",
46
+ "i3x-write": "nodes/i3x-write.js",
47
+ "i3x-history": "nodes/i3x-history.js",
48
+ "i3x-subscribe": "nodes/i3x-subscribe.js"
49
+ },
50
+ "examples": [
51
+ { "name": "i3x-complete-demo", "path": "examples/i3x-complete-demo.json" }
52
+ ]
53
+ },
54
+ "engines": {
55
+ "node": ">=14.0.0"
56
+ },
57
+ "author": "CESMII",
58
+ "homepage": "https://www.i3x.dev"
59
+ }