node-red-contrib-dmx-for-ha 0.1.2 → 0.1.6

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.
@@ -13,6 +13,16 @@
13
13
  inputs: 1,
14
14
  outputs: 0,
15
15
  inputLabels: ['Input'],
16
+ button: {
17
+ onclick: function() {
18
+ $.ajax({
19
+ url: 'ha-mqtt-button/' + this.id + '/add',
20
+ type: 'POST',
21
+ success: function() { RED.notify('device:add sent','success'); },
22
+ error: function() { RED.notify('Error — check NR log','error'); }
23
+ });
24
+ }
25
+ },
16
26
  paletteLabel: 'Button',
17
27
 
18
28
  defaults: {
@@ -19,21 +19,28 @@ module.exports = function (RED) {
19
19
 
20
20
  broker.register(node);
21
21
 
22
- // ── Broker connection feedback ────────────────────────────────
23
- setStatus('yellow', 'ring', 'Connecting to broker...');
22
+ // ── Auto-discovery based on Discovery Mode ────────────────────
23
+ const discoveryMode = config.discoveryMode || 'enabled';
24
+
25
+ function autoDiscover() {
26
+ if (discoveryMode === 'disabled') {
27
+ setStatus('grey', 'ring', 'Disabled — not discovered');
28
+ return;
29
+ }
30
+ // Small delay to allow broker connection to stabilise
31
+ setTimeout(function () {
32
+ handleDeviceAdd();
33
+ }, 2000);
34
+ }
35
+
24
36
  broker.on('connect', function () {
25
- setStatus('grey', 'ring', 'Connected — awaiting device:add');
26
- });
27
- broker.on('close', function () {
28
- setStatus('red', 'ring', 'Broker disconnected');
29
- });
30
- broker.on('error', function (err) {
31
- node.warn('MQTT broker error: ' + err.message);
32
- setStatus('red', 'dot', 'Broker error — check config');
37
+ autoDiscover();
33
38
  });
34
39
 
35
- // ── Discovery mode ─────────────────────────────────────────
36
- const discoveryMode = config.discoveryMode || 'enabled';
40
+
41
+
42
+
43
+
37
44
 
38
45
  // ── Node settings ─────────────────────────────────────────
39
46
  const S = {
@@ -170,5 +177,19 @@ module.exports = function (RED) {
170
177
  });
171
178
  }
172
179
 
180
+
181
+ // ── HTTP endpoints for canvas buttons — registered once at module level ──
182
+ RED.httpAdmin.post('/ha-mqtt-button/:id/add', RED.auth.needsPermission('ha-mqtt-button.write'), function(req, res) {
183
+ const n = RED.nodes.getNode(req.params.id);
184
+ if (n) { n.receive({ device: 'add' }); res.sendStatus(200); }
185
+ else res.sendStatus(404);
186
+ });
187
+
188
+ RED.httpAdmin.post('/ha-mqtt-button/:id/remove', RED.auth.needsPermission('ha-mqtt-button.write'), function(req, res) {
189
+ const n = RED.nodes.getNode(req.params.id);
190
+ if (n) { n.receive({ device: 'remove' }); res.sendStatus(200); }
191
+ else res.sendStatus(404);
192
+ });
193
+
173
194
  RED.nodes.registerType('ha-mqtt-button', HaMqttButtonNode);
174
195
  };
@@ -8,7 +8,7 @@
8
8
  RED.nodes.registerType('ha-mqtt-config', {
9
9
  category: 'config',
10
10
  defaults: {
11
- label: { value: '', required: true },
11
+ name: { value: '', required: true },
12
12
  siteId: { value: '', required: true },
13
13
  zone: { value: '', required: true },
14
14
  broker: { value: '', type: 'mqtt-broker', required: true },
@@ -43,10 +43,10 @@
43
43
 
44
44
  <!-- NAME -->
45
45
  <div class="form-row">
46
- <label for="node-config-input-label">
46
+ <label for="node-config-input-name">
47
47
  <i class="fa fa-tag"></i> Config Label
48
48
  </label>
49
- <input type="text" id="node-config-input-label"
49
+ <input type="text" id="node-config-input-name"
50
50
  placeholder="e.g. Master Zone, Guest Wing" />
51
51
  <div style="margin-left:106px; margin-top:4px; color:#999; font-size:0.85em;">
52
52
  Give this config a friendly label so you can find it in the node dropdowns
@@ -14,6 +14,16 @@
14
14
  outputs: 1,
15
15
  outputLabels: ['Link'],
16
16
  inputLabels: ['Input'],
17
+ button: {
18
+ onclick: function() {
19
+ $.ajax({
20
+ url: 'ha-mqtt-dmx-group/' + this.id + '/add',
21
+ type: 'POST',
22
+ success: function() { RED.notify('device:add sent','success'); },
23
+ error: function() { RED.notify('Error — check NR log','error'); }
24
+ });
25
+ }
26
+ },
17
27
  paletteLabel: 'DMX Group',
18
28
 
19
29
  defaults: {
@@ -22,21 +22,28 @@ module.exports = function (RED) {
22
22
 
23
23
  broker.register(node);
24
24
 
25
- // ── Broker connection feedback ────────────────────────────────
26
- setStatus('yellow', 'ring', 'Connecting to broker...');
25
+ // ── Auto-discovery based on Discovery Mode ────────────────────
26
+ const discoveryMode = config.discoveryMode || 'enabled';
27
+
28
+ function autoDiscover() {
29
+ if (discoveryMode === 'disabled') {
30
+ setStatus('grey', 'ring', 'Disabled — not discovered');
31
+ return;
32
+ }
33
+ // Small delay to allow broker connection to stabilise
34
+ setTimeout(function () {
35
+ handleDeviceAdd();
36
+ }, 2000);
37
+ }
38
+
27
39
  broker.on('connect', function () {
28
- setStatus('grey', 'ring', 'Connected — awaiting device:add');
29
- });
30
- broker.on('close', function () {
31
- setStatus('red', 'ring', 'Broker disconnected');
32
- });
33
- broker.on('error', function (err) {
34
- node.warn('MQTT broker error: ' + err.message);
35
- setStatus('red', 'dot', 'Broker error — check config');
40
+ autoDiscover();
36
41
  });
37
42
 
38
- // ── Discovery mode ─────────────────────────────────────────
39
- const discoveryMode = config.discoveryMode || 'enabled';
43
+
44
+
45
+
46
+
40
47
 
41
48
  // ── Node settings ─────────────────────────────────────────
42
49
  const S = {
@@ -66,12 +73,19 @@ module.exports = function (RED) {
66
73
  const cmdTopic = `${groupTopic}/${cfg.commandTopic}`;
67
74
 
68
75
  // ── Context helpers ───────────────────────────────────────
76
+ // Check disk store available once on startup
77
+ let diskAvailable = false;
78
+ try { node.context().get('__test', 'disk'); diskAvailable = true; }
79
+ catch(e) { diskAvailable = false; }
80
+
69
81
  function ctxGet(key, store) {
70
- try { return node.context().get(key, store); }
82
+ if (store === 'disk' && !diskAvailable) return node.context().get(key);
83
+ try { return node.context().get(key, store || undefined); }
71
84
  catch(e) { return node.context().get(key); }
72
85
  }
73
86
  function ctxSet(key, val, store) {
74
- try { node.context().set(key, val, store); }
87
+ if (store === 'disk' && !diskAvailable) { node.context().set(key, val); return; }
88
+ try { node.context().set(key, val, store || undefined); }
75
89
  catch(e) { node.context().set(key, val); }
76
90
  }
77
91
  function recall(ramKey, diskKey, fallback) {
@@ -277,5 +291,19 @@ module.exports = function (RED) {
277
291
  });
278
292
  }
279
293
 
294
+
295
+ // ── HTTP endpoints for canvas buttons — registered once at module level ──
296
+ RED.httpAdmin.post('/ha-mqtt-dmx-group/:id/add', RED.auth.needsPermission('ha-mqtt-dmx-group.write'), function(req, res) {
297
+ const n = RED.nodes.getNode(req.params.id);
298
+ if (n) { n.receive({ device: 'add' }); res.sendStatus(200); }
299
+ else res.sendStatus(404);
300
+ });
301
+
302
+ RED.httpAdmin.post('/ha-mqtt-dmx-group/:id/remove', RED.auth.needsPermission('ha-mqtt-dmx-group.write'), function(req, res) {
303
+ const n = RED.nodes.getNode(req.params.id);
304
+ if (n) { n.receive({ device: 'remove' }); res.sendStatus(200); }
305
+ else res.sendStatus(404);
306
+ });
307
+
280
308
  RED.nodes.registerType('ha-mqtt-dmx-group', HaMqttDmxGroupNode);
281
309
  };
@@ -122,6 +122,16 @@
122
122
  icon: 'font-awesome/fa-lightbulb-o',
123
123
  inputs: 1,
124
124
  outputs: 0,
125
+ button: {
126
+ onclick: function() {
127
+ $.ajax({
128
+ url: 'ha-mqtt-dmx/' + this.id + '/add',
129
+ type: 'POST',
130
+ success: function() { RED.notify('device:add sent','success'); },
131
+ error: function() { RED.notify('Error — check NR log','error'); }
132
+ });
133
+ }
134
+ },
125
135
  paletteLabel: 'DMX',
126
136
 
127
137
  defaults: {
@@ -217,14 +227,6 @@
217
227
  placeholder="Optional — defaults to fixture ID e.g. L-992-A" />
218
228
  </div>
219
229
 
220
- <!-- CONFIG -->
221
- <div class="form-row">
222
- <label for="node-input-config">
223
- <i class="fa fa-cog"></i> Config
224
- </label>
225
- <input type="text" id="node-input-config" />
226
- </div>
227
-
228
230
  <!-- Discovery Mode -->
229
231
  <div class="form-row">
230
232
  <label for="node-input-discoveryMode">
@@ -338,6 +340,14 @@
338
340
  </select>
339
341
  </div>
340
342
 
343
+ <!-- CONFIG -->
344
+ <div class="form-row">
345
+ <label for="node-input-config">
346
+ <i class="fa fa-cog"></i> Config
347
+ </label>
348
+ <input type="text" id="node-input-config" />
349
+ </div>
350
+
341
351
  <!-- 5. Area -->
342
352
  <div class="form-row">
343
353
  <label for="node-input-area">
@@ -29,21 +29,28 @@ module.exports = function (RED) {
29
29
 
30
30
  broker.register(node);
31
31
 
32
- // ── Broker connection feedback ────────────────────────────────
33
- setStatus('yellow', 'ring', 'Connecting to broker...');
32
+ // ── Auto-discovery based on Discovery Mode ────────────────────
33
+ const discoveryMode = config.discoveryMode || 'enabled';
34
+
35
+ function autoDiscover() {
36
+ if (discoveryMode === 'disabled') {
37
+ setStatus('grey', 'ring', 'Disabled — not discovered');
38
+ return;
39
+ }
40
+ // Small delay to allow broker connection to stabilise
41
+ setTimeout(function () {
42
+ handleDeviceAdd();
43
+ }, 2000);
44
+ }
45
+
34
46
  broker.on('connect', function () {
35
- setStatus('grey', 'ring', 'Connected — awaiting device:add');
36
- });
37
- broker.on('close', function () {
38
- setStatus('red', 'ring', 'Broker disconnected');
39
- });
40
- broker.on('error', function (err) {
41
- node.warn('MQTT broker error: ' + err.message);
42
- setStatus('red', 'dot', 'Broker error — check config');
47
+ autoDiscover();
43
48
  });
44
49
 
45
- // ── Discovery mode ─────────────────────────────────────────
46
- const discoveryMode = config.discoveryMode || 'enabled';
50
+
51
+
52
+
53
+
47
54
 
48
55
  // ── Node settings ─────────────────────────────────────────
49
56
  const S = {
@@ -87,12 +94,19 @@ module.exports = function (RED) {
87
94
  const dmxTopic = `${cfg.siteId}/${cfg.zone}/dmx/${S.universe}`;
88
95
 
89
96
  // ── Context helpers ───────────────────────────────────────
97
+ // Check disk store available once on startup
98
+ let diskAvailable = false;
99
+ try { node.context().get('__test', 'disk'); diskAvailable = true; }
100
+ catch(e) { diskAvailable = false; }
101
+
90
102
  function ctxGet(key, store) {
91
- try { return node.context().get(key, store); }
103
+ if (store === 'disk' && !diskAvailable) return node.context().get(key);
104
+ try { return node.context().get(key, store || undefined); }
92
105
  catch(e) { return node.context().get(key); }
93
106
  }
94
107
  function ctxSet(key, val, store) {
95
- try { node.context().set(key, val, store); }
108
+ if (store === 'disk' && !diskAvailable) { node.context().set(key, val); return; }
109
+ try { node.context().set(key, val, store || undefined); }
96
110
  catch(e) { node.context().set(key, val); }
97
111
  }
98
112
  function recall(ramKey, diskKey, fallback) {
@@ -549,5 +563,19 @@ module.exports = function (RED) {
549
563
  });
550
564
  }
551
565
 
566
+
567
+ // ── HTTP endpoints for canvas buttons — registered once at module level ──
568
+ RED.httpAdmin.post('/ha-mqtt-dmx/:id/add', RED.auth.needsPermission('ha-mqtt-dmx.write'), function(req, res) {
569
+ const n = RED.nodes.getNode(req.params.id);
570
+ if (n) { n.receive({ device: 'add' }); res.sendStatus(200); }
571
+ else res.sendStatus(404);
572
+ });
573
+
574
+ RED.httpAdmin.post('/ha-mqtt-dmx/:id/remove', RED.auth.needsPermission('ha-mqtt-dmx.write'), function(req, res) {
575
+ const n = RED.nodes.getNode(req.params.id);
576
+ if (n) { n.receive({ device: 'remove' }); res.sendStatus(200); }
577
+ else res.sendStatus(404);
578
+ });
579
+
552
580
  RED.nodes.registerType('ha-mqtt-dmx', HaMqttDmxNode);
553
581
  };
@@ -13,6 +13,16 @@
13
13
  inputs: 1,
14
14
  outputs: 0,
15
15
  inputLabels: ['Input'],
16
+ button: {
17
+ onclick: function() {
18
+ $.ajax({
19
+ url: 'ha-mqtt-pir/' + this.id + '/add',
20
+ type: 'POST',
21
+ success: function() { RED.notify('device:add sent','success'); },
22
+ error: function() { RED.notify('Error — check NR log','error'); }
23
+ });
24
+ }
25
+ },
16
26
  paletteLabel: 'PIR',
17
27
 
18
28
  defaults: {
@@ -19,21 +19,28 @@ module.exports = function (RED) {
19
19
 
20
20
  broker.register(node);
21
21
 
22
- // ── Broker connection feedback ────────────────────────────────
23
- setStatus('yellow', 'ring', 'Connecting to broker...');
22
+ // ── Auto-discovery based on Discovery Mode ────────────────────
23
+ const discoveryMode = config.discoveryMode || 'enabled';
24
+
25
+ function autoDiscover() {
26
+ if (discoveryMode === 'disabled') {
27
+ setStatus('grey', 'ring', 'Disabled — not discovered');
28
+ return;
29
+ }
30
+ // Small delay to allow broker connection to stabilise
31
+ setTimeout(function () {
32
+ handleDeviceAdd();
33
+ }, 2000);
34
+ }
35
+
24
36
  broker.on('connect', function () {
25
- setStatus('grey', 'ring', 'Connected — awaiting device:add');
26
- });
27
- broker.on('close', function () {
28
- setStatus('red', 'ring', 'Broker disconnected');
29
- });
30
- broker.on('error', function (err) {
31
- node.warn('MQTT broker error: ' + err.message);
32
- setStatus('red', 'dot', 'Broker error — check config');
37
+ autoDiscover();
33
38
  });
34
39
 
35
- // ── Discovery mode ─────────────────────────────────────────
36
- const discoveryMode = config.discoveryMode || 'enabled';
40
+
41
+
42
+
43
+
37
44
 
38
45
  // ── Node settings ─────────────────────────────────────────
39
46
  const S = {
@@ -195,5 +202,19 @@ module.exports = function (RED) {
195
202
  });
196
203
  }
197
204
 
205
+
206
+ // ── HTTP endpoints for canvas buttons — registered once at module level ──
207
+ RED.httpAdmin.post('/ha-mqtt-pir/:id/add', RED.auth.needsPermission('ha-mqtt-pir.write'), function(req, res) {
208
+ const n = RED.nodes.getNode(req.params.id);
209
+ if (n) { n.receive({ device: 'add' }); res.sendStatus(200); }
210
+ else res.sendStatus(404);
211
+ });
212
+
213
+ RED.httpAdmin.post('/ha-mqtt-pir/:id/remove', RED.auth.needsPermission('ha-mqtt-pir.write'), function(req, res) {
214
+ const n = RED.nodes.getNode(req.params.id);
215
+ if (n) { n.receive({ device: 'remove' }); res.sendStatus(200); }
216
+ else res.sendStatus(404);
217
+ });
218
+
198
219
  RED.nodes.registerType('ha-mqtt-pir', HaMqttPirNode);
199
220
  };
@@ -13,6 +13,16 @@
13
13
  inputs: 1,
14
14
  outputs: 0,
15
15
  inputLabels: ['Input'],
16
+ button: {
17
+ onclick: function() {
18
+ $.ajax({
19
+ url: 'ha-mqtt-relay/' + this.id + '/add',
20
+ type: 'POST',
21
+ success: function() { RED.notify('device:add sent','success'); },
22
+ error: function() { RED.notify('Error — check NR log','error'); }
23
+ });
24
+ }
25
+ },
16
26
  paletteLabel: 'Relay',
17
27
 
18
28
  defaults: {
@@ -22,21 +22,28 @@ module.exports = function (RED) {
22
22
 
23
23
  broker.register(node);
24
24
 
25
- // ── Broker connection feedback ────────────────────────────────
26
- setStatus('yellow', 'ring', 'Connecting to broker...');
25
+ // ── Auto-discovery based on Discovery Mode ────────────────────
26
+ const discoveryMode = config.discoveryMode || 'enabled';
27
+
28
+ function autoDiscover() {
29
+ if (discoveryMode === 'disabled') {
30
+ setStatus('grey', 'ring', 'Disabled — not discovered');
31
+ return;
32
+ }
33
+ // Small delay to allow broker connection to stabilise
34
+ setTimeout(function () {
35
+ handleDeviceAdd();
36
+ }, 2000);
37
+ }
38
+
27
39
  broker.on('connect', function () {
28
- setStatus('grey', 'ring', 'Connected — awaiting device:add');
29
- });
30
- broker.on('close', function () {
31
- setStatus('red', 'ring', 'Broker disconnected');
32
- });
33
- broker.on('error', function (err) {
34
- node.warn('MQTT broker error: ' + err.message);
35
- setStatus('red', 'dot', 'Broker error — check config');
40
+ autoDiscover();
36
41
  });
37
42
 
38
- // ── Discovery mode ─────────────────────────────────────────
39
- const discoveryMode = config.discoveryMode || 'enabled';
43
+
44
+
45
+
46
+
40
47
 
41
48
  // ── Node settings ─────────────────────────────────────────
42
49
  const S = {
@@ -67,12 +74,19 @@ module.exports = function (RED) {
67
74
  const relayTopic = `${cfg.siteId}/${cfg.zone}/${S.controllerNum}/${S.mqttSegment}/${S.relayNum}`;
68
75
 
69
76
  // ── Context helpers ───────────────────────────────────────
77
+ // Check disk store available once on startup
78
+ let diskAvailable = false;
79
+ try { node.context().get('__test', 'disk'); diskAvailable = true; }
80
+ catch(e) { diskAvailable = false; }
81
+
70
82
  function ctxGet(key, store) {
71
- try { return node.context().get(key, store); }
83
+ if (store === 'disk' && !diskAvailable) return node.context().get(key);
84
+ try { return node.context().get(key, store || undefined); }
72
85
  catch(e) { return node.context().get(key); }
73
86
  }
74
87
  function ctxSet(key, val, store) {
75
- try { node.context().set(key, val, store); }
88
+ if (store === 'disk' && !diskAvailable) { node.context().set(key, val); return; }
89
+ try { node.context().set(key, val, store || undefined); }
76
90
  catch(e) { node.context().set(key, val); }
77
91
  }
78
92
  function recall(ramKey, diskKey, fallback) {
@@ -301,5 +315,19 @@ module.exports = function (RED) {
301
315
  });
302
316
  }
303
317
 
318
+
319
+ // ── HTTP endpoints for canvas buttons — registered once at module level ──
320
+ RED.httpAdmin.post('/ha-mqtt-relay/:id/add', RED.auth.needsPermission('ha-mqtt-relay.write'), function(req, res) {
321
+ const n = RED.nodes.getNode(req.params.id);
322
+ if (n) { n.receive({ device: 'add' }); res.sendStatus(200); }
323
+ else res.sendStatus(404);
324
+ });
325
+
326
+ RED.httpAdmin.post('/ha-mqtt-relay/:id/remove', RED.auth.needsPermission('ha-mqtt-relay.write'), function(req, res) {
327
+ const n = RED.nodes.getNode(req.params.id);
328
+ if (n) { n.receive({ device: 'remove' }); res.sendStatus(200); }
329
+ else res.sendStatus(404);
330
+ });
331
+
304
332
  RED.nodes.registerType('ha-mqtt-relay', HaMqttRelayNode);
305
333
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-dmx-for-ha",
3
- "version": "0.1.2",
3
+ "version": "0.1.6",
4
4
  "description": "DMX lighting control for Home Assistant via Node-RED and MQTT. Place a node, fill in the settings, deploy. Full HA device registry integration with RGBW/RGBWW/CCT/brightness colour modes, transitions, effects, and group control.",
5
5
  "keywords": [
6
6
  "node-red",