node-red-contrib-dmx-for-ha 0.6.14 → 0.6.16
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 +31 -0
- package/nodes/ha-mqtt-button.js +18 -0
- package/nodes/ha-mqtt-dmx-group.js +19 -0
- package/nodes/ha-mqtt-dmx.js +23 -0
- package/nodes/ha-mqtt-pir.js +18 -0
- package/nodes/ha-mqtt-relay.js +18 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -226,6 +226,37 @@ Typical workflow: Remove → update node settings → Deploy → node auto-disco
|
|
|
226
226
|
|
|
227
227
|
---
|
|
228
228
|
|
|
229
|
+
## System control topic
|
|
230
|
+
|
|
231
|
+
All nodes subscribe to a system control topic for **bulk add/remove during commissioning**. No wiring needed — publish one MQTT message and all matching nodes respond.
|
|
232
|
+
|
|
233
|
+
**Topic:** `{siteId}/system/control` (e.g. `MW3D/system/control`)
|
|
234
|
+
|
|
235
|
+
**Payload:**
|
|
236
|
+
```json
|
|
237
|
+
{"cmd": "remove", "zone": "all", "type": "all"}
|
|
238
|
+
{"cmd": "add", "zone": "Master", "type": "dmx"}
|
|
239
|
+
{"cmd": "remove", "zone": "BnB", "type": "button"}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
| Field | Values | Description |
|
|
243
|
+
|---|---|---|
|
|
244
|
+
| `cmd` | `add`, `remove` | Add or remove HA discovery |
|
|
245
|
+
| `zone` | `all`, `Master`, `BnB` | Matches config node zone |
|
|
246
|
+
| `type` | `all`, `dmx`, `button`, `pir`, `relay` | Node type filter |
|
|
247
|
+
|
|
248
|
+
**Commissioning workflow:**
|
|
249
|
+
```
|
|
250
|
+
1. ADD Master DMX → test all lights
|
|
251
|
+
2. REMOVE Master DMX → fix wrong names/channels
|
|
252
|
+
3. ADD Master DMX → verify clean
|
|
253
|
+
4. Move to next type: Button → PIR → Relay
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
A **System Control flow** ships with the package (`system_control_flow.json`). Import it into Node-RED, connect the MQTT out node to your broker, and you have one-click bulk control per zone and type.
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
229
260
|
## DMX Group Node
|
|
230
261
|
|
|
231
262
|
Appears as a single light entity in HA. Commands fan out to all nodes on its **Link** output.
|
package/nodes/ha-mqtt-button.js
CHANGED
|
@@ -70,6 +70,23 @@ module.exports = function (RED) {
|
|
|
70
70
|
handleDeviceAdd();
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
// ── System control topic ─────────────────────────────────
|
|
74
|
+
const systemTopic = `${cfg.siteId}/system/control`;
|
|
75
|
+
broker.subscribe(systemTopic, 0, function (topic, rawPayload) {
|
|
76
|
+
let msg;
|
|
77
|
+
try { msg = JSON.parse(rawPayload.toString()); } catch(e) { return; }
|
|
78
|
+
if (!msg.cmd) return;
|
|
79
|
+
const zone = (msg.zone || 'all').toLowerCase();
|
|
80
|
+
if (zone !== 'all' && zone !== cfg.zone.toLowerCase()) return;
|
|
81
|
+
const type = (msg.type || 'all').toLowerCase();
|
|
82
|
+
if (type !== 'all' && type !== 'button') return;
|
|
83
|
+
if (msg.cmd === 'remove') {
|
|
84
|
+
handleDeviceRemove();
|
|
85
|
+
} else if (msg.cmd === 'add') {
|
|
86
|
+
_tryDiscover();
|
|
87
|
+
}
|
|
88
|
+
}, node.id + '_sys');
|
|
89
|
+
|
|
73
90
|
// Auto-discover if broker already connected on deploy
|
|
74
91
|
if (broker.connected) {
|
|
75
92
|
_tryDiscover();
|
|
@@ -268,6 +285,7 @@ module.exports = function (RED) {
|
|
|
268
285
|
|
|
269
286
|
// ── Device remove ─────────────────────────────────────────
|
|
270
287
|
function handleDeviceRemove() {
|
|
288
|
+
_discovered = false; // Allow re-discovery after remove
|
|
271
289
|
unregisterFixtureId();
|
|
272
290
|
pub(cfgTopic, '', true);
|
|
273
291
|
pub(uiBtnCfgTopic, '', true);
|
|
@@ -70,6 +70,24 @@ module.exports = function (RED) {
|
|
|
70
70
|
handleDeviceAdd();
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
// ── System control topic ─────────────────────────────────
|
|
74
|
+
const systemTopic = `${cfg.siteId}/system/control`;
|
|
75
|
+
broker.subscribe(systemTopic, 0, function (topic, rawPayload) {
|
|
76
|
+
let msg;
|
|
77
|
+
try { msg = JSON.parse(rawPayload.toString()); } catch(e) { return; }
|
|
78
|
+
if (!msg.cmd) return;
|
|
79
|
+
const zone = (msg.zone || 'all').toLowerCase();
|
|
80
|
+
if (zone !== 'all' && zone !== cfg.zone.toLowerCase()) return;
|
|
81
|
+
const type = (msg.type || 'all').toLowerCase();
|
|
82
|
+
if (type !== 'all' && type !== 'dmx') return;
|
|
83
|
+
if (msg.cmd === 'remove') {
|
|
84
|
+
_discovered = false;
|
|
85
|
+
handleDeviceRemove(null);
|
|
86
|
+
} else if (msg.cmd === 'add') {
|
|
87
|
+
_tryDiscover();
|
|
88
|
+
}
|
|
89
|
+
}, node.id + '_sys');
|
|
90
|
+
|
|
73
91
|
// Auto-discover if broker already connected on deploy
|
|
74
92
|
if (broker.connected) {
|
|
75
93
|
_tryDiscover();
|
|
@@ -347,6 +365,7 @@ module.exports = function (RED) {
|
|
|
347
365
|
|
|
348
366
|
// ── Device remove ─────────────────────────────────────────
|
|
349
367
|
function handleDeviceRemove(incomingTrace) {
|
|
368
|
+
_discovered = false; // Allow re-discovery after remove
|
|
350
369
|
if (diskTimer) { clearTimeout(diskTimer); diskTimer = null; }
|
|
351
370
|
// No flush needed on remove — state is cleared below
|
|
352
371
|
// Keep disk state on remove — state survives remove/add cycles
|
package/nodes/ha-mqtt-dmx.js
CHANGED
|
@@ -78,6 +78,28 @@ module.exports = function (RED) {
|
|
|
78
78
|
handleDeviceAdd();
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
// ── System control topic ─────────────────────────────────
|
|
82
|
+
// Subscribes to: {siteId}/system/control
|
|
83
|
+
// Payload: {"cmd":"remove","zone":"all"} or {"cmd":"add","zone":"Master"}
|
|
84
|
+
const systemTopic = `${cfg.siteId}/system/control`;
|
|
85
|
+
broker.subscribe(systemTopic, 0, function (topic, rawPayload) {
|
|
86
|
+
let msg;
|
|
87
|
+
try { msg = JSON.parse(rawPayload.toString()); } catch(e) { return; }
|
|
88
|
+
if (!msg.cmd) return;
|
|
89
|
+
// Zone filter — "all" or match config zone
|
|
90
|
+
const zone = (msg.zone || 'all').toLowerCase();
|
|
91
|
+
if (zone !== 'all' && zone !== cfg.zone.toLowerCase()) return;
|
|
92
|
+
// Type filter — "all" or match node type
|
|
93
|
+
const type = (msg.type || 'all').toLowerCase();
|
|
94
|
+
if (type !== 'all' && type !== 'dmx') return;
|
|
95
|
+
// Execute command
|
|
96
|
+
if (msg.cmd === 'remove') {
|
|
97
|
+
handleDeviceRemove();
|
|
98
|
+
} else if (msg.cmd === 'add') {
|
|
99
|
+
_tryDiscover();
|
|
100
|
+
}
|
|
101
|
+
}, node.id + '_sys');
|
|
102
|
+
|
|
81
103
|
// Auto-discover if broker already connected on deploy
|
|
82
104
|
if (broker.connected) {
|
|
83
105
|
_tryDiscover();
|
|
@@ -775,6 +797,7 @@ module.exports = function (RED) {
|
|
|
775
797
|
|
|
776
798
|
// ── Device remove ─────────────────────────────────────────
|
|
777
799
|
function handleDeviceRemove() {
|
|
800
|
+
_discovered = false; // Allow re-discovery after remove
|
|
778
801
|
unregisterFixtureId();
|
|
779
802
|
clearChannelRegistry();
|
|
780
803
|
stopEffect();
|
package/nodes/ha-mqtt-pir.js
CHANGED
|
@@ -67,6 +67,23 @@ module.exports = function (RED) {
|
|
|
67
67
|
handleDeviceAdd();
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
// ── System control topic ─────────────────────────────────
|
|
71
|
+
const systemTopic = `${cfg.siteId}/system/control`;
|
|
72
|
+
broker.subscribe(systemTopic, 0, function (topic, rawPayload) {
|
|
73
|
+
let msg;
|
|
74
|
+
try { msg = JSON.parse(rawPayload.toString()); } catch(e) { return; }
|
|
75
|
+
if (!msg.cmd) return;
|
|
76
|
+
const zone = (msg.zone || 'all').toLowerCase();
|
|
77
|
+
if (zone !== 'all' && zone !== cfg.zone.toLowerCase()) return;
|
|
78
|
+
const type = (msg.type || 'all').toLowerCase();
|
|
79
|
+
if (type !== 'all' && type !== 'pir') return;
|
|
80
|
+
if (msg.cmd === 'remove') {
|
|
81
|
+
handleDeviceRemove();
|
|
82
|
+
} else if (msg.cmd === 'add') {
|
|
83
|
+
_tryDiscover();
|
|
84
|
+
}
|
|
85
|
+
}, node.id + '_sys');
|
|
86
|
+
|
|
70
87
|
// Auto-discover if broker already connected on deploy
|
|
71
88
|
if (broker.connected) {
|
|
72
89
|
_tryDiscover();
|
|
@@ -301,6 +318,7 @@ module.exports = function (RED) {
|
|
|
301
318
|
|
|
302
319
|
// ── Device remove ─────────────────────────────────────────
|
|
303
320
|
function handleDeviceRemove() {
|
|
321
|
+
_discovered = false; // Allow re-discovery after remove
|
|
304
322
|
unregisterFixtureId();
|
|
305
323
|
cancelWarmup();
|
|
306
324
|
pub(avtyTopic, 'offline', true);
|
package/nodes/ha-mqtt-relay.js
CHANGED
|
@@ -70,6 +70,23 @@ module.exports = function (RED) {
|
|
|
70
70
|
handleDeviceAdd();
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
// ── System control topic ─────────────────────────────────
|
|
74
|
+
const systemTopic = `${cfg.siteId}/system/control`;
|
|
75
|
+
broker.subscribe(systemTopic, 0, function (topic, rawPayload) {
|
|
76
|
+
let msg;
|
|
77
|
+
try { msg = JSON.parse(rawPayload.toString()); } catch(e) { return; }
|
|
78
|
+
if (!msg.cmd) return;
|
|
79
|
+
const zone = (msg.zone || 'all').toLowerCase();
|
|
80
|
+
if (zone !== 'all' && zone !== cfg.zone.toLowerCase()) return;
|
|
81
|
+
const type = (msg.type || 'all').toLowerCase();
|
|
82
|
+
if (type !== 'all' && type !== 'relay') return;
|
|
83
|
+
if (msg.cmd === 'remove') {
|
|
84
|
+
handleDeviceRemove();
|
|
85
|
+
} else if (msg.cmd === 'add') {
|
|
86
|
+
_tryDiscover();
|
|
87
|
+
}
|
|
88
|
+
}, node.id + '_sys');
|
|
89
|
+
|
|
73
90
|
// Auto-discover if broker already connected on deploy
|
|
74
91
|
if (broker.connected) {
|
|
75
92
|
_tryDiscover();
|
|
@@ -388,6 +405,7 @@ module.exports = function (RED) {
|
|
|
388
405
|
|
|
389
406
|
// ── Device remove ─────────────────────────────────────────
|
|
390
407
|
function handleDeviceRemove() {
|
|
408
|
+
_discovered = false; // Allow re-discovery after remove
|
|
391
409
|
unregisterFixtureId();
|
|
392
410
|
stopEffect();
|
|
393
411
|
if (diskTimer) { clearTimeout(diskTimer); diskTimer = null; }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-dmx-for-ha",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.16",
|
|
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",
|