@andreydk1981/node-red-dashboard-2-ui-projector 0.1.18 → 0.1.19
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/README.md +21 -45
- package/nodes/ui-projector.html +123 -124
- package/nodes/ui-projector.js +2 -2
- package/package.json +4 -5
- package/nodes/projector-command.html +0 -76
- package/nodes/projector-command.js +0 -60
package/README.md
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
# Node-RED
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
- `ui-multimedia-projector`: Dashboard 2.0 widget with projector UI and ON/OFF actions.
|
|
7
|
-
- `ui-projector`: legacy alias for backward compatibility with existing flows.
|
|
8
|
-
- `projector-command`: helper node that normalizes different ON/OFF inputs to stable commands.
|
|
1
|
+
# Node-RED Dashboard 2.0 - Projector Widget
|
|
2
|
+
|
|
3
|
+
**Release note (v0.1.6):** added compatibility metadata (Node.js >=16, Node-RED >=3.1.15) and example flow.
|
|
4
|
+
|
|
5
|
+
A simple Node-RED Dashboard 2.0 widget that displays a projector icon.
|
|
9
6
|
|
|
10
7
|
## Installation
|
|
11
8
|
|
|
@@ -21,9 +18,9 @@ npm run build
|
|
|
21
18
|
|
|
22
19
|
3. Link to your Node-RED installation (for development):
|
|
23
20
|
```bash
|
|
24
|
-
npm link
|
|
25
|
-
cd ~/.node-red
|
|
26
|
-
npm link @andreydk1981/node-red-dashboard-2-ui-projector
|
|
21
|
+
npm link
|
|
22
|
+
cd ~/.node-red
|
|
23
|
+
npm link @andreydk1981/node-red-dashboard-2-ui-projector
|
|
27
24
|
```
|
|
28
25
|
|
|
29
26
|
4. Restart Node-RED
|
|
@@ -37,41 +34,20 @@ npm run dev
|
|
|
37
34
|
|
|
38
35
|
Then open http://localhost:5173 in your browser.
|
|
39
36
|
|
|
40
|
-
## Usage
|
|
41
|
-
|
|
42
|
-
After installation, both nodes appear in the Node-RED palette:
|
|
43
|
-
- `ui-multimedia-projector` in Dashboard category.
|
|
44
|
-
- `ui-projector` (legacy, kept for old projects).
|
|
45
|
-
- `projector-command` in Function category.
|
|
46
|
-
|
|
47
|
-
Typical flow:
|
|
48
|
-
`inject/switch -> projector-command -> tcp/serial/request node`
|
|
49
|
-
|
|
50
|
-
## Structure
|
|
51
|
-
|
|
52
|
-
- `/nodes` - Node-RED node definition files
|
|
53
|
-
- `/ui` - Vue.js component files
|
|
54
|
-
- `/resources` - Built widget files (generated)
|
|
55
|
-
- `vite.config.mjs` - Vite build configuration
|
|
56
|
-
- `package.json` - Package definition
|
|
57
|
-
|
|
58
|
-
## Add new node in this package
|
|
59
|
-
|
|
60
|
-
1. Create `nodes/<node-name>.js` and register type with `RED.nodes.registerType`.
|
|
61
|
-
2. Create `nodes/<node-name>.html` with editor form and help.
|
|
62
|
-
3. Add the node entry to `package.json`:
|
|
63
|
-
```json
|
|
64
|
-
"node-red": {
|
|
65
|
-
"nodes": {
|
|
66
|
-
"<node-name>": "nodes/<node-name>.js"
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
```
|
|
70
|
-
4. If it is a Dashboard 2.0 widget, also add metadata in `node-red-dashboard-2.widgets` and build the UI bundle.
|
|
71
|
-
5. Restart Node-RED and verify the new node appears in the palette.
|
|
37
|
+
## Usage
|
|
72
38
|
|
|
73
|
-
|
|
39
|
+
After installation, you'll find the "ui-projector" node in the Node-RED palette under the Dashboard category. Drag it onto your flow, configure it to be part of a Dashboard 2.0 group, and deploy.
|
|
74
40
|
|
|
75
|
-
|
|
41
|
+
The widget will display a projector icon on your dashboard.
|
|
76
42
|
|
|
43
|
+
## Structure
|
|
77
44
|
|
|
45
|
+
- `/nodes` - Node-RED node definition files
|
|
46
|
+
- `/ui` - Vue.js component files
|
|
47
|
+
- `/resources` - Built widget files (generated)
|
|
48
|
+
- `vite.config.mjs` - Vite build configuration
|
|
49
|
+
- `package.json` - Package definition
|
|
50
|
+
|
|
51
|
+
## License
|
|
52
|
+
|
|
53
|
+
Apache-2.0
|
package/nodes/ui-projector.html
CHANGED
|
@@ -1,124 +1,123 @@
|
|
|
1
|
-
<script type="text/javascript">
|
|
2
|
-
RED.nodes.registerType('ui-projector', {
|
|
3
|
-
category: RED._('@flowfuse/node-red-dashboard/ui-base:ui-base.label.category'),
|
|
4
|
-
color: RED._('@flowfuse/node-red-dashboard/ui-base:ui-base.colors.light'),
|
|
5
|
-
defaults: {
|
|
6
|
-
name: { value: "" },
|
|
7
|
-
group: { type: 'ui-group', required: true },
|
|
8
|
-
order: { value: 0 },
|
|
9
|
-
width: {
|
|
10
|
-
value: 0,
|
|
11
|
-
validate: function (v) {
|
|
12
|
-
const width = v || 0
|
|
13
|
-
const currentGroup = $('#node-input-group').val() || this.group
|
|
14
|
-
const groupNode = RED.nodes.node(currentGroup)
|
|
15
|
-
const valid = !groupNode || +width <= +groupNode.width
|
|
16
|
-
$('#node-input-size').toggleClass('input-error', !valid)
|
|
17
|
-
return valid
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
height: { value: 0 }
|
|
21
|
-
},
|
|
22
|
-
inputs: 1,
|
|
23
|
-
outputs: 1,
|
|
24
|
-
icon: "font-awesome/fa-video-camera",
|
|
25
|
-
label: function() {
|
|
26
|
-
return this.name || "ui-projector";
|
|
27
|
-
},
|
|
28
|
-
oneditprepare: function () {
|
|
29
|
-
$('#node-input-size').elementSizer({
|
|
30
|
-
width: '#node-input-width',
|
|
31
|
-
height: '#node-input-height',
|
|
32
|
-
group: '#node-input-group'
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
</script>
|
|
37
|
-
|
|
38
|
-
<script type="text/html" data-template-name="ui-projector">
|
|
39
|
-
<div class="form-row">
|
|
40
|
-
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
41
|
-
<input type="text" id="node-input-name" placeholder="Name">
|
|
42
|
-
</div>
|
|
43
|
-
<div class="form-row">
|
|
44
|
-
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
|
|
45
|
-
<input type="text" id="node-input-group">
|
|
46
|
-
</div>
|
|
47
|
-
<div class="form-row">
|
|
48
|
-
<label><i class="fa fa-object-group"></i> <span data-i18n="ui-projector.label.size"></label>
|
|
49
|
-
<input type="hidden" id="node-input-width">
|
|
50
|
-
<input type="hidden" id="node-input-height">
|
|
51
|
-
<button class="editor-button" id="node-input-size"></button>
|
|
52
|
-
</div>
|
|
53
|
-
</script>
|
|
54
|
-
|
|
55
|
-
<script type="text/html" data-help-name="ui-projector">
|
|
56
|
-
<p>Dashboard 2.0 widget with a projector icon.</p>
|
|
57
|
-
|
|
58
|
-
<h3>Properties</h3>
|
|
59
|
-
<dl class="message-properties">
|
|
60
|
-
<dt>Name <span class="property-type">string</span></dt>
|
|
61
|
-
<dd>The widget name displayed above the icon. Can be updated using <code>msg.name</code>.</dd>
|
|
62
|
-
</dl>
|
|
63
|
-
|
|
64
|
-
<h3>Incoming messages</h3>
|
|
65
|
-
<dl class="message-properties">
|
|
66
|
-
<dt>msg.name <span class="property-type">string</span></dt>
|
|
67
|
-
<dd>Set a new name for the widget. The name is persisted and used as <code>msg.topic</code> for outgoing messages.</dd>
|
|
68
|
-
<dt>msg.color <span class="property-type">string</span></dt>
|
|
69
|
-
<dd>Set the icon color (any CSS color). To reset, send <code>msg.color = null</code>.</dd>
|
|
70
|
-
<dt>msg.ires <span class="property-type">string</span></dt>
|
|
71
|
-
<dd>Set resolution text displayed under the icon (e.g. <code>"1920x1080"</code>).</dd>
|
|
72
|
-
</dl>
|
|
73
|
-
|
|
74
|
-
<h3>Behavior</h3>
|
|
75
|
-
<p>When the <strong>ON</strong> button is pressed the widget sends <code>msg.payload = "%1POWR 1"</code>. When the <strong>OFF</strong> button is pressed it sends <code>msg.payload = "%1POWR 0"</code>. Outgoing <code>msg.topic</code> is the widget Name.</p>
|
|
76
|
-
|
|
77
|
-
<h3>Example flow</h3>
|
|
78
|
-
<p>Import the JSON below into Node
|
|
79
|
-
<pre><code>{
|
|
80
|
-
"id": "example-1",
|
|
81
|
-
"type": "tab",
|
|
82
|
-
"label": "UIProjector example",
|
|
83
|
-
"nodes": [
|
|
84
|
-
{
|
|
85
|
-
"id": "n1",
|
|
86
|
-
"type": "ui-projector",
|
|
87
|
-
"z": "example-1",
|
|
88
|
-
"name": "Projector1",
|
|
89
|
-
"group": "your-dashboard-group-id",
|
|
90
|
-
"wires": [["debug1"]]
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
"id": "inject-on",
|
|
94
|
-
"type": "inject",
|
|
95
|
-
"z": "example-1",
|
|
96
|
-
"name": "Send ON string",
|
|
97
|
-
"props": [{"p":"payload","v":"%1POWR 1","vt":"str"}],
|
|
98
|
-
"topic": "",
|
|
99
|
-
"wires": [["n1"]]
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
"id": "inject-off",
|
|
103
|
-
"type": "inject",
|
|
104
|
-
"z": "example-1",
|
|
105
|
-
"name": "Send OFF string",
|
|
106
|
-
"props": [{"p":"payload","v":"%1POWR 0","vt":"str"}],
|
|
107
|
-
"topic": "",
|
|
108
|
-
"wires": [["n1"]]
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
"id": "debug1",
|
|
112
|
-
"type": "debug",
|
|
113
|
-
"z": "example-1",
|
|
114
|
-
"name": "debug",
|
|
115
|
-
"active": true,
|
|
116
|
-
"complete": "payload"
|
|
117
|
-
}
|
|
118
|
-
]
|
|
119
|
-
}</code></pre>
|
|
120
|
-
|
|
121
|
-
<h3>Details</h3>
|
|
122
|
-
<p>The widget saves the last received color and resolution and restores them on reload. Icon and text scale with widget size.</p>
|
|
123
|
-
</script>
|
|
124
|
-
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType('ui-projector', {
|
|
3
|
+
category: RED._('@flowfuse/node-red-dashboard/ui-base:ui-base.label.category'),
|
|
4
|
+
color: RED._('@flowfuse/node-red-dashboard/ui-base:ui-base.colors.light'),
|
|
5
|
+
defaults: {
|
|
6
|
+
name: { value: "" },
|
|
7
|
+
group: { type: 'ui-group', required: true },
|
|
8
|
+
order: { value: 0 },
|
|
9
|
+
width: {
|
|
10
|
+
value: 0,
|
|
11
|
+
validate: function (v) {
|
|
12
|
+
const width = v || 0
|
|
13
|
+
const currentGroup = $('#node-input-group').val() || this.group
|
|
14
|
+
const groupNode = RED.nodes.node(currentGroup)
|
|
15
|
+
const valid = !groupNode || +width <= +groupNode.width
|
|
16
|
+
$('#node-input-size').toggleClass('input-error', !valid)
|
|
17
|
+
return valid
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
height: { value: 0 }
|
|
21
|
+
},
|
|
22
|
+
inputs: 1,
|
|
23
|
+
outputs: 1,
|
|
24
|
+
icon: "font-awesome/fa-video-camera",
|
|
25
|
+
label: function() {
|
|
26
|
+
return this.name || "ui-projector";
|
|
27
|
+
},
|
|
28
|
+
oneditprepare: function () {
|
|
29
|
+
$('#node-input-size').elementSizer({
|
|
30
|
+
width: '#node-input-width',
|
|
31
|
+
height: '#node-input-height',
|
|
32
|
+
group: '#node-input-group'
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<script type="text/html" data-template-name="ui-projector">
|
|
39
|
+
<div class="form-row">
|
|
40
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
41
|
+
<input type="text" id="node-input-name" placeholder="Name">
|
|
42
|
+
</div>
|
|
43
|
+
<div class="form-row">
|
|
44
|
+
<label for="node-input-group"><i class="fa fa-table"></i> Group</label>
|
|
45
|
+
<input type="text" id="node-input-group">
|
|
46
|
+
</div>
|
|
47
|
+
<div class="form-row">
|
|
48
|
+
<label><i class="fa fa-object-group"></i> <span data-i18n="ui-projector.label.size"></label>
|
|
49
|
+
<input type="hidden" id="node-input-width">
|
|
50
|
+
<input type="hidden" id="node-input-height">
|
|
51
|
+
<button class="editor-button" id="node-input-size"></button>
|
|
52
|
+
</div>
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<script type="text/html" data-help-name="ui-projector">
|
|
56
|
+
<p>Dashboard 2.0 widget with a projector icon.</p>
|
|
57
|
+
|
|
58
|
+
<h3>Properties</h3>
|
|
59
|
+
<dl class="message-properties">
|
|
60
|
+
<dt>Name <span class="property-type">string</span></dt>
|
|
61
|
+
<dd>The widget name displayed above the icon. Can be updated using <code>msg.name</code>.</dd>
|
|
62
|
+
</dl>
|
|
63
|
+
|
|
64
|
+
<h3>Incoming messages</h3>
|
|
65
|
+
<dl class="message-properties">
|
|
66
|
+
<dt>msg.name <span class="property-type">string</span></dt>
|
|
67
|
+
<dd>Set a new name for the widget. The name is persisted and used as <code>msg.topic</code> for outgoing messages.</dd>
|
|
68
|
+
<dt>msg.color <span class="property-type">string</span></dt>
|
|
69
|
+
<dd>Set the icon color (any CSS color). To reset, send <code>msg.color = null</code>.</dd>
|
|
70
|
+
<dt>msg.ires <span class="property-type">string</span></dt>
|
|
71
|
+
<dd>Set resolution text displayed under the icon (e.g. <code>"1920x1080"</code>).</dd>
|
|
72
|
+
</dl>
|
|
73
|
+
|
|
74
|
+
<h3>Behavior</h3>
|
|
75
|
+
<p>When the <strong>ON</strong> button is pressed the widget sends <code>msg.payload = "%1POWR 1"</code>. When the <strong>OFF</strong> button is pressed it sends <code>msg.payload = "%1POWR 0"</code>. Outgoing <code>msg.topic</code> is the widget Name.</p>
|
|
76
|
+
|
|
77
|
+
<h3>Example flow</h3>
|
|
78
|
+
<p>Import the JSON below into Node‑RED (Menu → Import → Clipboard):</p>
|
|
79
|
+
<pre><code>{
|
|
80
|
+
"id": "example-1",
|
|
81
|
+
"type": "tab",
|
|
82
|
+
"label": "UIProjector example",
|
|
83
|
+
"nodes": [
|
|
84
|
+
{
|
|
85
|
+
"id": "n1",
|
|
86
|
+
"type": "ui-projector",
|
|
87
|
+
"z": "example-1",
|
|
88
|
+
"name": "Projector1",
|
|
89
|
+
"group": "your-dashboard-group-id",
|
|
90
|
+
"wires": [["debug1"]]
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"id": "inject-on",
|
|
94
|
+
"type": "inject",
|
|
95
|
+
"z": "example-1",
|
|
96
|
+
"name": "Send ON string",
|
|
97
|
+
"props": [{"p":"payload","v":"%1POWR 1","vt":"str"}],
|
|
98
|
+
"topic": "",
|
|
99
|
+
"wires": [["n1"]]
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"id": "inject-off",
|
|
103
|
+
"type": "inject",
|
|
104
|
+
"z": "example-1",
|
|
105
|
+
"name": "Send OFF string",
|
|
106
|
+
"props": [{"p":"payload","v":"%1POWR 0","vt":"str"}],
|
|
107
|
+
"topic": "",
|
|
108
|
+
"wires": [["n1"]]
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"id": "debug1",
|
|
112
|
+
"type": "debug",
|
|
113
|
+
"z": "example-1",
|
|
114
|
+
"name": "debug",
|
|
115
|
+
"active": true,
|
|
116
|
+
"complete": "payload"
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
}</code></pre>
|
|
120
|
+
|
|
121
|
+
<h3>Details</h3>
|
|
122
|
+
<p>The widget saves the last received color and resolution and restores them on reload. Icon and text scale with widget size.</p>
|
|
123
|
+
</script>
|
package/nodes/ui-projector.js
CHANGED
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@andreydk1981/node-red-dashboard-2-ui-projector",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"description": "A Node-RED
|
|
7
|
+
"description": "A Node-RED Dashboard 2.0 widget with a projector icon",
|
|
8
8
|
"keywords": [
|
|
9
9
|
"node-red",
|
|
10
10
|
"node-red-node",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git",
|
|
22
|
-
"url": "
|
|
22
|
+
"url": "https://github.com/andreydk1981/node-red-dashboard-2-ui-projector.git"
|
|
23
23
|
},
|
|
24
24
|
"bugs": {
|
|
25
25
|
"url": "https://github.com/andreydk1981/node-red-dashboard-2-ui-projector/issues"
|
|
@@ -28,8 +28,7 @@
|
|
|
28
28
|
"node-red": {
|
|
29
29
|
"version": ">=3.1.15 <5.0.0",
|
|
30
30
|
"nodes": {
|
|
31
|
-
"ui-projector": "nodes/ui-projector.js"
|
|
32
|
-
"projector-command": "nodes/projector-command.js"
|
|
31
|
+
"ui-projector": "nodes/ui-projector.js"
|
|
33
32
|
}
|
|
34
33
|
},
|
|
35
34
|
"node-red-dashboard-2": {
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
<script type="text/javascript">
|
|
2
|
-
RED.nodes.registerType('projector-command', {
|
|
3
|
-
category: 'function',
|
|
4
|
-
color: '#dedede',
|
|
5
|
-
defaults: {
|
|
6
|
-
name: { value: '' },
|
|
7
|
-
topic: { value: '' },
|
|
8
|
-
commandFormat: { value: 'onoff' },
|
|
9
|
-
onValue: { value: 'ON' },
|
|
10
|
-
offValue: { value: 'OFF' }
|
|
11
|
-
},
|
|
12
|
-
inputs: 1,
|
|
13
|
-
outputs: 1,
|
|
14
|
-
icon: 'font-awesome/fa-terminal',
|
|
15
|
-
label: function () {
|
|
16
|
-
return this.name || 'projector-command'
|
|
17
|
-
},
|
|
18
|
-
oneditprepare: function () {
|
|
19
|
-
function toggleValues () {
|
|
20
|
-
var mode = $('#node-input-commandFormat').val()
|
|
21
|
-
var disabled = mode === 'pjlink'
|
|
22
|
-
$('#node-input-onValue').prop('disabled', disabled)
|
|
23
|
-
$('#node-input-offValue').prop('disabled', disabled)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
$('#node-input-commandFormat').on('change', toggleValues)
|
|
27
|
-
toggleValues()
|
|
28
|
-
}
|
|
29
|
-
})
|
|
30
|
-
</script>
|
|
31
|
-
|
|
32
|
-
<script type="text/html" data-template-name="projector-command">
|
|
33
|
-
<div class="form-row">
|
|
34
|
-
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
35
|
-
<input type="text" id="node-input-name" placeholder="Name">
|
|
36
|
-
</div>
|
|
37
|
-
<div class="form-row">
|
|
38
|
-
<label for="node-input-topic"><i class="fa fa-tasks"></i> Topic</label>
|
|
39
|
-
<input type="text" id="node-input-topic" placeholder="projector-1">
|
|
40
|
-
</div>
|
|
41
|
-
<div class="form-row">
|
|
42
|
-
<label for="node-input-commandFormat"><i class="fa fa-cogs"></i> Format</label>
|
|
43
|
-
<select id="node-input-commandFormat">
|
|
44
|
-
<option value="onoff">ON/OFF</option>
|
|
45
|
-
<option value="pjlink">PJLink (%1POWR 1/0)</option>
|
|
46
|
-
</select>
|
|
47
|
-
</div>
|
|
48
|
-
<div class="form-row">
|
|
49
|
-
<label for="node-input-onValue"><i class="fa fa-arrow-up"></i> ON value</label>
|
|
50
|
-
<input type="text" id="node-input-onValue">
|
|
51
|
-
</div>
|
|
52
|
-
<div class="form-row">
|
|
53
|
-
<label for="node-input-offValue"><i class="fa fa-arrow-down"></i> OFF value</label>
|
|
54
|
-
<input type="text" id="node-input-offValue">
|
|
55
|
-
</div>
|
|
56
|
-
</script>
|
|
57
|
-
|
|
58
|
-
<script type="text/html" data-help-name="projector-command">
|
|
59
|
-
<p>Converts various ON/OFF inputs into stable control commands.</p>
|
|
60
|
-
|
|
61
|
-
<h3>Input</h3>
|
|
62
|
-
<dl class="message-properties">
|
|
63
|
-
<dt>msg.command <span class="property-type">string | boolean | number</span></dt>
|
|
64
|
-
<dd>Optional command value. If present, it has priority over <code>msg.payload</code>.</dd>
|
|
65
|
-
<dt>msg.payload <span class="property-type">string | boolean | number</span></dt>
|
|
66
|
-
<dd>Supports <code>true/false</code>, <code>1/0</code>, <code>ON/OFF</code>, and <code>%1POWR 1/0</code>.</dd>
|
|
67
|
-
</dl>
|
|
68
|
-
|
|
69
|
-
<h3>Output</h3>
|
|
70
|
-
<dl class="message-properties">
|
|
71
|
-
<dt>msg.payload <span class="property-type">string</span></dt>
|
|
72
|
-
<dd>Formatted command in selected mode (ON/OFF, PJLink, or custom values).</dd>
|
|
73
|
-
<dt>msg.topic <span class="property-type">string</span></dt>
|
|
74
|
-
<dd>Set from node config if the incoming message does not contain a topic.</dd>
|
|
75
|
-
</dl>
|
|
76
|
-
</script>
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
module.exports = function (RED) {
|
|
2
|
-
function ProjectorCommandNode (config) {
|
|
3
|
-
RED.nodes.createNode(this, config)
|
|
4
|
-
const node = this
|
|
5
|
-
|
|
6
|
-
node.topic = config.topic || ''
|
|
7
|
-
node.commandFormat = config.commandFormat || 'onoff'
|
|
8
|
-
node.onValue = config.onValue || 'ON'
|
|
9
|
-
node.offValue = config.offValue || 'OFF'
|
|
10
|
-
|
|
11
|
-
function normalizeState (msg) {
|
|
12
|
-
const value = typeof msg.command !== 'undefined' ? msg.command : msg.payload
|
|
13
|
-
if (typeof value === 'boolean') {
|
|
14
|
-
return value
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (typeof value === 'number') {
|
|
18
|
-
if (value === 1) return true
|
|
19
|
-
if (value === 0) return false
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (typeof value === 'string') {
|
|
23
|
-
const normalized = value.trim().toLowerCase()
|
|
24
|
-
if (['on', '1', 'true', '%1powr 1'].includes(normalized)) return true
|
|
25
|
-
if (['off', '0', 'false', '%1powr 0'].includes(normalized)) return false
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return null
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function formatPayload (isOn) {
|
|
32
|
-
if (node.commandFormat === 'pjlink') {
|
|
33
|
-
return isOn ? '%1POWR 1' : '%1POWR 0'
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return isOn ? node.onValue : node.offValue
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
node.on('input', function (msg, send, done) {
|
|
40
|
-
const state = normalizeState(msg)
|
|
41
|
-
if (state === null) {
|
|
42
|
-
node.status({ fill: 'red', shape: 'ring', text: 'unsupported payload' })
|
|
43
|
-
if (done) done()
|
|
44
|
-
return
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
msg.payload = formatPayload(state)
|
|
48
|
-
if (!msg.topic && node.topic) {
|
|
49
|
-
msg.topic = node.topic
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
node.status({ fill: 'green', shape: 'dot', text: state ? 'ON' : 'OFF' })
|
|
53
|
-
send(msg)
|
|
54
|
-
|
|
55
|
-
if (done) done()
|
|
56
|
-
})
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
RED.nodes.registerType('projector-command', ProjectorCommandNode)
|
|
60
|
-
}
|