node-red-contrib-dmx-for-ha 0.1.0 → 0.1.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.
@@ -8,7 +8,7 @@
8
8
 
9
9
  RED.nodes.registerType('ha-mqtt-button', {
10
10
  category: 'DMX for HA',
11
- color: '#27ae60',
11
+ color: '#27ae60',
12
12
  icon: 'font-awesome/fa-hand-pointer-o',
13
13
  inputs: 1,
14
14
  outputs: 0,
@@ -17,6 +17,7 @@
17
17
 
18
18
  defaults: {
19
19
  name: { value: '' },
20
+ discoveryMode: { value: 'enabled' },
20
21
  config: { value: '', type: 'ha-mqtt-config', required: true },
21
22
  // Identity
22
23
  uid: { value: '', required: true },
@@ -27,8 +28,8 @@
27
28
  subLocation: { value: '' },
28
29
  // Button specifics
29
30
  buttonPosition: { value: '' },
30
- buttonPayload: { value: '', required: true },
31
- subscribeTopic: { value: 'buttons' },
31
+ buttonPayload: { value: '', required: true },
32
+ subscribeTopic: { value: '', required: true },
32
33
  // Options
33
34
  haIcon: { value: 'mdi:gesture-tap-button' },
34
35
  ledColor: { value: 'Blue' },
@@ -140,13 +141,23 @@
140
141
  placeholder="Optional — defaults to S-10-A on canvas" />
141
142
  </div>
142
143
 
144
+ <!-- Discovery Mode -->
143
145
  <div class="form-row">
144
- <label for="node-input-config">
145
- <i class="fa fa-cog"></i> Config
146
+ <label for="node-input-discoveryMode">
147
+ <i class="fa fa-toggle-on"></i> Discovery Mode
146
148
  </label>
147
- <input type="text" id="node-input-config" />
149
+ <select id="node-input-discoveryMode" style="width:55%">
150
+ <option value="enabled">Enabled — discovered and visible in HA</option>
151
+ <option value="hidden">Hidden — discovered but hidden in HA dashboard</option>
152
+ <option value="disabled">Disabled — not discovered, not in HA</option>
153
+ </select>
154
+ <div style="margin-left:106px; margin-top:4px; color:#999; font-size:0.85em;">
155
+ Use <strong>Disabled</strong> for future fixtures not yet wired.
156
+ Use <strong>Hidden</strong> for fixtures installed but not ready for the homeowner.
157
+ </div>
148
158
  </div>
149
159
 
160
+
150
161
  <hr/>
151
162
 
152
163
  <!-- ── BUTTON (* Required) ───────────────────────────────── -->
@@ -164,18 +175,46 @@
164
175
  <input type="text" id="node-input-uid"
165
176
  placeholder="10" style="width:70px" />
166
177
  &nbsp;
167
- <select id="node-input-uidPostfix" style="width:65px">
178
+ <select id="node-input-uidPostfix" style="width:90px">
168
179
  <option value="">(none)</option>
169
180
  <option value="-A">-A</option>
170
181
  <option value="-B">-B</option>
171
182
  <option value="-C">-C</option>
172
183
  <option value="-D">-D</option>
184
+ <option value="-E">-E</option>
185
+ <option value="-F">-F</option>
186
+ <option value="-G">-G</option>
187
+ <option value="-H">-H</option>
188
+ <option value="-J">-J</option>
189
+ <option value="-K">-K</option>
190
+ <option value="-L">-L</option>
191
+ <option value="-M">-M</option>
192
+ <option value="-N">-N</option>
193
+ <option value="-P">-P</option>
194
+ <option value="-Q">-Q</option>
195
+ <option value="-R">-R</option>
196
+ <option value="-S">-S</option>
197
+ <option value="-T">-T</option>
198
+ <option value="-U">-U</option>
199
+ <option value="-V">-V</option>
200
+ <option value="-W">-W</option>
201
+ <option value="-X">-X</option>
202
+ <option value="-Y">-Y</option>
203
+ <option value="-Z">-Z</option>
173
204
  </select>
174
205
  <span style="margin-left:8px; color:#999; font-size:0.85em;">
175
206
  Plan ID — Button letter
176
207
  </span>
177
208
  </div>
178
209
 
210
+ <div class="form-row">
211
+ <div class="form-row">
212
+ <label for="node-input-config">
213
+ <i class="fa fa-cog"></i> Config
214
+ </label>
215
+ <input type="text" id="node-input-config" />
216
+ </div>
217
+
179
218
  <div class="form-row">
180
219
  <label for="node-input-area">
181
220
  <i class="fa fa-map-marker"></i> Area
@@ -248,7 +287,7 @@
248
287
  <i class="fa fa-exchange"></i> Subscribe topic
249
288
  </label>
250
289
  <input type="text" id="node-input-subscribeTopic"
251
- placeholder="buttons" style="width:55%" />
290
+ placeholder="Required — e.g. buttons or home/zone/buttons" style="width:55%" />
252
291
  </div>
253
292
 
254
293
  <hr/>
@@ -19,6 +19,22 @@ module.exports = function (RED) {
19
19
 
20
20
  broker.register(node);
21
21
 
22
+ // ── Broker connection feedback ────────────────────────────────
23
+ setStatus('yellow', 'ring', 'Connecting to broker...');
24
+ 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');
33
+ });
34
+
35
+ // ── Discovery mode ─────────────────────────────────────────
36
+ const discoveryMode = config.discoveryMode || 'enabled';
37
+
22
38
  // ── Node settings ─────────────────────────────────────────
23
39
  const S = {
24
40
  uid: config.uid || '',
@@ -8,7 +8,7 @@
8
8
  RED.nodes.registerType('ha-mqtt-config', {
9
9
  category: 'config',
10
10
  defaults: {
11
- name: { value: '', required: true },
11
+ label: { value: '', required: true },
12
12
  siteId: { value: '', required: true },
13
13
  zone: { value: '', required: true },
14
14
  broker: { value: '', type: 'mqtt-broker', required: true },
@@ -20,7 +20,9 @@
20
20
  commandTopic: { value: 'cmd' },
21
21
  availTopic: { value: 'avty' },
22
22
  enabledDefault: { value: 'true' },
23
- diskDelay: { value: '10' },
23
+ diskDelay: { value: '10' },
24
+ transitionRateLimit: { value: '1' },
25
+ transitionHaUiTime: { value: '1' },
24
26
  flashShort: { value: '1' },
25
27
  flashLong: { value: '10' },
26
28
  },
@@ -41,11 +43,15 @@
41
43
 
42
44
  <!-- NAME -->
43
45
  <div class="form-row">
44
- <label for="node-config-input-name">
45
- <i class="fa fa-tag"></i> Name
46
+ <label for="node-config-input-label">
47
+ <i class="fa fa-tag"></i> Config Label
46
48
  </label>
47
- <input type="text" id="node-config-input-name"
49
+ <input type="text" id="node-config-input-label"
48
50
  placeholder="e.g. Master Zone, Guest Wing" />
51
+ <div style="margin-left:106px; margin-top:4px; color:#999; font-size:0.85em;">
52
+ Give this config a friendly label so you can find it in the node dropdowns
53
+ — e.g. "My House" or "Master Zone". Don't stress — this can be changed at any time.
54
+ </div>
49
55
  </div>
50
56
 
51
57
  <hr/>
@@ -77,8 +83,8 @@
77
83
  placeholder="e.g. Master, BnB, GuestWing"
78
84
  style="width:60%" />
79
85
  <div style="margin-left:106px; margin-top:4px; color:#999; font-size:0.85em;">
80
- Used in MQTT topics — no spaces or special characters ( # + / ).
81
- Spaces are automatically converted to underscores.
86
+ Physical zone name used in your MQTT topics — e.g. <code>Master</code>, <code>BnB</code>, <code>GuestWing</code>.
87
+ Keep it short with no spaces. This can be updated later if needed.
82
88
  </div>
83
89
  </div>
84
90
 
@@ -57,7 +57,9 @@ module.exports = function (RED) {
57
57
  // Timing defaults
58
58
  this.diskDelay = parseInt(config.diskDelay) || 10;
59
59
  this.flashShort = parseFloat(config.flashShort) || 1;
60
- this.flashLong = parseFloat(config.flashLong) || 10;
60
+ this.flashLong = parseFloat(config.flashLong) || 10;
61
+ this.transitionRateLimit = parseFloat(config.transitionRateLimit) || 1;
62
+ this.transitionHaUiTime = parseFloat(config.transitionHaUiTime) || 1;
61
63
 
62
64
  // Expose a convenience settings object for child nodes
63
65
  this.settings = {
@@ -73,7 +75,9 @@ module.exports = function (RED) {
73
75
  enabledDefault: this.enabledDefault,
74
76
  diskDelay: this.diskDelay,
75
77
  flashShort: this.flashShort,
76
- flashLong: this.flashLong,
78
+ flashLong: this.flashLong,
79
+ transitionRateLimit: this.transitionRateLimit,
80
+ transitionHaUiTime: this.transitionHaUiTime,
77
81
  };
78
82
  }
79
83
 
@@ -8,7 +8,7 @@
8
8
 
9
9
  RED.nodes.registerType('ha-mqtt-dmx-group', {
10
10
  category: 'DMX for HA',
11
- color: '#9b3fd4',
11
+ color: '#d4a017',
12
12
  icon: 'font-awesome/fa-object-group',
13
13
  inputs: 1,
14
14
  outputs: 1,
@@ -160,6 +160,23 @@
160
160
  <input type="text" id="node-input-config" />
161
161
  </div>
162
162
 
163
+ <!-- Discovery Mode -->
164
+ <div class="form-row">
165
+ <label for="node-input-discoveryMode">
166
+ <i class="fa fa-toggle-on"></i> Discovery Mode
167
+ </label>
168
+ <select id="node-input-discoveryMode" style="width:55%">
169
+ <option value="enabled">Enabled — discovered and visible in HA</option>
170
+ <option value="hidden">Hidden — discovered but hidden in HA dashboard</option>
171
+ <option value="disabled">Disabled — not discovered, not in HA</option>
172
+ </select>
173
+ <div style="margin-left:106px; margin-top:4px; color:#999; font-size:0.85em;">
174
+ Use <strong>Disabled</strong> for future fixtures not yet wired.
175
+ Use <strong>Hidden</strong> for fixtures installed but not ready for the homeowner.
176
+ </div>
177
+ </div>
178
+
179
+
163
180
  <hr/>
164
181
 
165
182
  <!-- ── GROUP (* Required) ────────────────────────────────── -->
@@ -192,12 +209,32 @@
192
209
  placeholder="992" style="width:70px"
193
210
  title="Cable/plan ID number — prefix LG is fixed for groups" />
194
211
  &nbsp;
195
- <select id="node-input-uidPostfix" style="width:65px">
212
+ <select id="node-input-uidPostfix" style="width:90px">
196
213
  <option value="">(none)</option>
197
214
  <option value="-A">-A</option>
198
215
  <option value="-B">-B</option>
199
216
  <option value="-C">-C</option>
200
217
  <option value="-D">-D</option>
218
+ <option value="-E">-E</option>
219
+ <option value="-F">-F</option>
220
+ <option value="-G">-G</option>
221
+ <option value="-H">-H</option>
222
+ <option value="-J">-J</option>
223
+ <option value="-K">-K</option>
224
+ <option value="-L">-L</option>
225
+ <option value="-M">-M</option>
226
+ <option value="-N">-N</option>
227
+ <option value="-P">-P</option>
228
+ <option value="-Q">-Q</option>
229
+ <option value="-R">-R</option>
230
+ <option value="-S">-S</option>
231
+ <option value="-T">-T</option>
232
+ <option value="-U">-U</option>
233
+ <option value="-V">-V</option>
234
+ <option value="-W">-W</option>
235
+ <option value="-X">-X</option>
236
+ <option value="-Y">-Y</option>
237
+ <option value="-Z">-Z</option>
201
238
  </select>
202
239
  <span style="margin-left:8px; color:#999; font-size:0.85em;">
203
240
  Plan ID — Channel (if applicable)
@@ -229,6 +266,14 @@
229
266
  </select>
230
267
  </div>
231
268
 
269
+ <!-- CONFIG -->
270
+ <div class="form-row">
271
+ <label for="node-input-config">
272
+ <i class="fa fa-cog"></i> Config
273
+ </label>
274
+ <input type="text" id="node-input-config" />
275
+ </div>
276
+
232
277
  <!-- Area -->
233
278
  <div class="form-row">
234
279
  <label for="node-input-area">
@@ -22,6 +22,22 @@ module.exports = function (RED) {
22
22
 
23
23
  broker.register(node);
24
24
 
25
+ // ── Broker connection feedback ────────────────────────────────
26
+ setStatus('yellow', 'ring', 'Connecting to broker...');
27
+ 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');
36
+ });
37
+
38
+ // ── Discovery mode ─────────────────────────────────────────
39
+ const discoveryMode = config.discoveryMode || 'enabled';
40
+
25
41
  // ── Node settings ─────────────────────────────────────────
26
42
  const S = {
27
43
  groupName: config.groupName || '',
@@ -191,8 +207,8 @@ module.exports = function (RED) {
191
207
  setStatus('green', 'ring', `${groupId} discovery sent`);
192
208
  node.log(`Group device added: "${S.groupName || groupId}"`);
193
209
 
194
- // Children receive device:add directly from the SYSTEM node
195
- // No forwarding needed via Link
210
+ // Forward device:add to children via Link so they self-discover
211
+ node.send([{ device: 'add' }]);
196
212
 
197
213
  // Recovery
198
214
  setTimeout(() => {
@@ -118,7 +118,7 @@
118
118
  // ── Node Registration ──────────────────────────────────────────
119
119
  RED.nodes.registerType('ha-mqtt-dmx', {
120
120
  category: 'DMX for HA',
121
- color: '#ae45ff',
121
+ color: '#f0b429',
122
122
  icon: 'font-awesome/fa-lightbulb-o',
123
123
  inputs: 1,
124
124
  outputs: 0,
@@ -126,6 +126,7 @@
126
126
 
127
127
  defaults: {
128
128
  name: { value: '' },
129
+ discoveryMode: { value: 'enabled' },
129
130
  config: { value: '', type: 'ha-mqtt-config', required: true },
130
131
  // Fixture identity
131
132
  colorMode: { value: 'rgbw', required: true },
@@ -150,7 +151,7 @@
150
151
  haIcon: { value: 'mdi:lightbulb' },
151
152
  showEffects: { value: true },
152
153
  transitions: { value: true },
153
- groupSync: { value: false },
154
+ groupSync: { value: true },
154
155
  defaultState: { value: 'OFF' },
155
156
  // Advanced
156
157
  dmxLimiter: { value: '255' },
@@ -207,7 +208,7 @@
207
208
  ============================================================ -->
208
209
  <script type="text/html" data-template-name="ha-mqtt-dmx">
209
210
 
210
- <!-- NAME (optional — defaults to fixture ID on canvas) -->
211
+ <!-- NAME -->
211
212
  <div class="form-row">
212
213
  <label for="node-input-name">
213
214
  <i class="fa fa-tag"></i> Name
@@ -216,7 +217,7 @@
216
217
  placeholder="Optional — defaults to fixture ID e.g. L-992-A" />
217
218
  </div>
218
219
 
219
- <!-- CONFIG NODE PICKER -->
220
+ <!-- CONFIG -->
220
221
  <div class="form-row">
221
222
  <label for="node-input-config">
222
223
  <i class="fa fa-cog"></i> Config
@@ -224,6 +225,23 @@
224
225
  <input type="text" id="node-input-config" />
225
226
  </div>
226
227
 
228
+ <!-- Discovery Mode -->
229
+ <div class="form-row">
230
+ <label for="node-input-discoveryMode">
231
+ <i class="fa fa-toggle-on"></i> Discovery Mode
232
+ </label>
233
+ <select id="node-input-discoveryMode" style="width:55%">
234
+ <option value="enabled">Enabled — discovered and visible in HA</option>
235
+ <option value="hidden">Hidden — discovered but hidden in HA dashboard</option>
236
+ <option value="disabled">Disabled — not discovered, not in HA</option>
237
+ </select>
238
+ <div style="margin-left:106px; margin-top:4px; color:#999; font-size:0.85em;">
239
+ Use <strong>Disabled</strong> for future fixtures not yet wired.
240
+ Use <strong>Hidden</strong> for fixtures installed but not ready for the homeowner.
241
+ </div>
242
+ </div>
243
+
244
+
227
245
  <hr/>
228
246
 
229
247
  <!-- ── FIXTURE (* Required) ──────────────────────────────── -->
@@ -233,32 +251,7 @@
233
251
  </label>
234
252
  </div>
235
253
 
236
- <!-- Colour Mode -->
237
- <div class="form-row">
238
- <label for="node-input-colorMode">
239
- <i class="fa fa-sliders"></i> Colour Mode
240
- </label>
241
- <select id="node-input-colorMode" style="width:55%">
242
- <option value="rgbw">RGBW</option>
243
- <option value="rgbww">RGBWW</option>
244
- <option value="rgb">RGB</option>
245
- <option value="color_temp">Colour Temperature (CCT)</option>
246
- <option value="brightness">Brightness only</option>
247
- <option value="onoff">On/Off only</option>
248
- </select>
249
- </div>
250
-
251
- <!-- Device Type -->
252
- <div class="form-row">
253
- <label for="node-input-deviceType">
254
- <i class="fa fa-lightbulb-o"></i> Device Type
255
- </label>
256
- <input type="text" id="node-input-deviceType"
257
- placeholder="e.g. Downlight, Strip light, Panel"
258
- style="width:55%" />
259
- </div>
260
-
261
- <!-- Prefix / ID / Postfix on one row -->
254
+ <!-- 1. Fixture ID -->
262
255
  <div class="form-row">
263
256
  <label for="node-input-uidPrefix">
264
257
  <i class="fa fa-tv"></i> Fixture ID
@@ -272,27 +265,64 @@
272
265
  placeholder="992" style="width:70px"
273
266
  title="Cable/plan ID number from electrical drawing" />
274
267
  &nbsp;
275
- <select id="node-input-uidPostfix" style="width:65px">
268
+ <select id="node-input-uidPostfix" style="width:80px">
276
269
  <option value="">(none)</option>
277
270
  <option value="-A">-A</option>
278
271
  <option value="-B">-B</option>
279
272
  <option value="-C">-C</option>
280
273
  <option value="-D">-D</option>
274
+ <option value="-E">-E</option>
275
+ <option value="-F">-F</option>
276
+ <option value="-G">-G</option>
277
+ <option value="-H">-H</option>
278
+ <option value="-J">-J</option>
279
+ <option value="-K">-K</option>
280
+ <option value="-L">-L</option>
281
+ <option value="-M">-M</option>
282
+ <option value="-N">-N</option>
283
+ <option value="-P">-P</option>
284
+ <option value="-Q">-Q</option>
285
+ <option value="-R">-R</option>
286
+ <option value="-S">-S</option>
287
+ <option value="-T">-T</option>
288
+ <option value="-U">-U</option>
289
+ <option value="-V">-V</option>
290
+ <option value="-W">-W</option>
291
+ <option value="-X">-X</option>
292
+ <option value="-Y">-Y</option>
293
+ <option value="-Z">-Z</option>
281
294
  </select>
282
295
  <span style="margin-left:8px; color:#999; font-size:0.85em;">
283
- Prefix — Plan ID — Channel
296
+ Prefix — Plan ID — Postfix
284
297
  </span>
285
298
  </div>
286
299
 
287
- <!-- Area -->
300
+ <!-- 2. Colour Mode -->
288
301
  <div class="form-row">
289
- <label for="node-input-area">
290
- <i class="fa fa-map-marker"></i> Area
302
+ <label for="node-input-colorMode">
303
+ <i class="fa fa-sliders"></i> Colour Mode
291
304
  </label>
292
- <select id="node-input-area" style="width:55%"></select>
305
+ <select id="node-input-colorMode" style="width:55%">
306
+ <option value="rgbw">RGBW</option>
307
+ <option value="rgbww">RGBWW</option>
308
+ <option value="rgb">RGB</option>
309
+ <option value="color_temp">Colour Temperature (CCT)</option>
310
+ <option value="brightness">Brightness only</option>
311
+ <option value="onoff">On/Off only</option>
312
+ </select>
293
313
  </div>
294
314
 
295
- <!-- Situation -->
315
+ <!-- 3. Device Type -->
316
+ <div class="form-row">
317
+ <label for="node-input-deviceType">
318
+ <i class="fa fa-lightbulb-o"></i> Device Type
319
+ </label>
320
+ <input type="text" id="node-input-deviceType"
321
+ placeholder="e.g. Downlight, Strip light, Panel"
322
+ style="width:55%" />
323
+ </div>
324
+
325
+ <!-- 4. Situation -->
296
326
  <div class="form-row">
297
327
  <label for="node-input-situation">
298
328
  <i class="fa fa-compass"></i> Situation
@@ -308,7 +338,15 @@
308
338
  </select>
309
339
  </div>
310
340
 
311
- <!-- Sub-Area -->
341
+ <!-- 5. Area -->
342
+ <div class="form-row">
343
+ <label for="node-input-area">
344
+ <i class="fa fa-map-marker"></i> Area
345
+ </label>
346
+ <select id="node-input-area" style="width:55%"></select>
347
+ </div>
348
+
349
+ <!-- 6. Sub-Area -->
312
350
  <div class="form-row">
313
351
  <label for="node-input-subLocation">
314
352
  <i class="fa fa-map-marker"></i> Sub-Area
@@ -318,6 +356,29 @@
318
356
 
319
357
  <hr/>
320
358
 
359
+ <!-- ── DMX CONTROLLER ────────────────────────────────────── -->
360
+ <div class="form-row">
361
+ <label style="width:100%; font-weight:bold; color:#999; font-size:0.85em; text-transform:uppercase; letter-spacing:0.05em;">
362
+ <i class="fa fa-sort-numeric-asc"></i> DMX Controller
363
+ </label>
364
+ </div>
365
+
366
+ <div class="form-row">
367
+ <label for="node-input-controllerNum">
368
+ <i class="fa fa-sort-numeric-asc"></i> Controller
369
+ </label>
370
+ <input type="number" id="node-input-controllerNum"
371
+ min="1" style="width:70px" />
372
+ &nbsp;&nbsp;
373
+ <label for="node-input-universe" style="width:auto">
374
+ Universe
375
+ </label>
376
+ <input type="number" id="node-input-universe"
377
+ min="1" style="width:70px" />
378
+ </div>
379
+
380
+ <hr/>
381
+
321
382
  <!-- ── DMX CHANNELS ──────────────────────────────────────── -->
322
383
  <div class="form-row">
323
384
  <label style="width:100%; font-weight:bold; color:#999; font-size:0.85em; text-transform:uppercase; letter-spacing:0.05em;">
@@ -367,29 +428,6 @@
367
428
 
368
429
  <hr/>
369
430
 
370
- <!-- ── DMX CONTROLLER ────────────────────────────────────── -->
371
- <div class="form-row">
372
- <label style="width:100%; font-weight:bold; color:#999; font-size:0.85em; text-transform:uppercase; letter-spacing:0.05em;">
373
- <i class="fa fa-sort-numeric-asc"></i> DMX Controller
374
- </label>
375
- </div>
376
-
377
- <div class="form-row">
378
- <label for="node-input-controllerNum">
379
- <i class="fa fa-sort-numeric-asc"></i> Controller
380
- </label>
381
- <input type="number" id="node-input-controllerNum"
382
- min="1" style="width:70px" />
383
- &nbsp;&nbsp;
384
- <label for="node-input-universe" style="width:auto">
385
- Universe
386
- </label>
387
- <input type="number" id="node-input-universe"
388
- min="1" style="width:70px" />
389
- </div>
390
-
391
- <hr/>
392
-
393
431
  <!-- ── OPTIONS ───────────────────────────────────────────── -->
394
432
  <div class="form-row">
395
433
  <label style="width:100%; font-weight:bold; color:#999; font-size:0.85em; text-transform:uppercase; letter-spacing:0.05em;">
@@ -457,7 +495,7 @@
457
495
  </label>
458
496
  <input type="number" id="node-input-dmxLimiter"
459
497
  min="0" max="255" style="width:70px" />
460
- <span style="margin-left:8px; color:#999; font-size:0.85em;">0–255</span>
498
+ <span style="margin-left:8px; color:#999; font-size:0.85em;">Caps all DMX channel values (0–255)</span>
461
499
  </div>
462
500
 
463
501
  <div class="form-row">
@@ -489,6 +527,8 @@
489
527
 
490
528
  </script>
491
529
 
530
+ </script>
531
+
492
532
  <!-- ============================================================
493
533
  Help Panel
494
534
  ============================================================ -->
@@ -29,6 +29,22 @@ module.exports = function (RED) {
29
29
 
30
30
  broker.register(node);
31
31
 
32
+ // ── Broker connection feedback ────────────────────────────────
33
+ setStatus('yellow', 'ring', 'Connecting to broker...');
34
+ 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');
43
+ });
44
+
45
+ // ── Discovery mode ─────────────────────────────────────────
46
+ const discoveryMode = config.discoveryMode || 'enabled';
47
+
32
48
  // ── Node settings ─────────────────────────────────────────
33
49
  const S = {
34
50
  uidPrefix: config.uidPrefix || 'L',
@@ -8,7 +8,7 @@
8
8
 
9
9
  RED.nodes.registerType('ha-mqtt-pir', {
10
10
  category: 'DMX for HA',
11
- color: '#2980b9',
11
+ color: '#9b59b6',
12
12
  icon: 'font-awesome/fa-podcast',
13
13
  inputs: 1,
14
14
  outputs: 0,
@@ -17,6 +17,7 @@
17
17
 
18
18
  defaults: {
19
19
  name: { value: '' },
20
+ discoveryMode: { value: 'enabled' },
20
21
  config: { value: '', type: 'ha-mqtt-config', required: true },
21
22
  // Identity
22
23
  uid: { value: '', required: true },
@@ -28,7 +29,7 @@
28
29
  // PIR specifics
29
30
  pirType: { value: 'Ceiling' },
30
31
  pirPayload: { value: '', required: true },
31
- subscribeTopic: { value: '' },
32
+ subscribeTopic: { value: '', required: true },
32
33
  // Options
33
34
  haIcon: { value: 'mdi:motion-sensor' },
34
35
  cableColor: { value: 'Purple' },
@@ -141,13 +142,23 @@
141
142
  placeholder="Optional — defaults to S-31 on canvas" />
142
143
  </div>
143
144
 
145
+ <!-- Discovery Mode -->
144
146
  <div class="form-row">
145
- <label for="node-input-config">
146
- <i class="fa fa-cog"></i> Config
147
+ <label for="node-input-discoveryMode">
148
+ <i class="fa fa-toggle-on"></i> Discovery Mode
147
149
  </label>
148
- <input type="text" id="node-input-config" />
150
+ <select id="node-input-discoveryMode" style="width:55%">
151
+ <option value="enabled">Enabled — discovered and visible in HA</option>
152
+ <option value="hidden">Hidden — discovered but hidden in HA dashboard</option>
153
+ <option value="disabled">Disabled — not discovered, not in HA</option>
154
+ </select>
155
+ <div style="margin-left:106px; margin-top:4px; color:#999; font-size:0.85em;">
156
+ Use <strong>Disabled</strong> for future fixtures not yet wired.
157
+ Use <strong>Hidden</strong> for fixtures installed but not ready for the homeowner.
158
+ </div>
149
159
  </div>
150
160
 
161
+
151
162
  <hr/>
152
163
 
153
164
  <!-- ── PIR (* Required) ──────────────────────────────────── -->
@@ -165,12 +176,32 @@
165
176
  <input type="text" id="node-input-uid"
166
177
  placeholder="31" style="width:70px" />
167
178
  &nbsp;
168
- <select id="node-input-uidPostfix" style="width:65px">
179
+ <select id="node-input-uidPostfix" style="width:90px">
169
180
  <option value="">(none)</option>
170
181
  <option value="-A">-A</option>
171
182
  <option value="-B">-B</option>
172
183
  <option value="-C">-C</option>
173
184
  <option value="-D">-D</option>
185
+ <option value="-E">-E</option>
186
+ <option value="-F">-F</option>
187
+ <option value="-G">-G</option>
188
+ <option value="-H">-H</option>
189
+ <option value="-J">-J</option>
190
+ <option value="-K">-K</option>
191
+ <option value="-L">-L</option>
192
+ <option value="-M">-M</option>
193
+ <option value="-N">-N</option>
194
+ <option value="-P">-P</option>
195
+ <option value="-Q">-Q</option>
196
+ <option value="-R">-R</option>
197
+ <option value="-S">-S</option>
198
+ <option value="-T">-T</option>
199
+ <option value="-U">-U</option>
200
+ <option value="-V">-V</option>
201
+ <option value="-W">-W</option>
202
+ <option value="-X">-X</option>
203
+ <option value="-Y">-Y</option>
204
+ <option value="-Z">-Z</option>
174
205
  </select>
175
206
  <span style="margin-left:8px; color:#999; font-size:0.85em;">
176
207
  Plan ID — Sensor group
@@ -190,6 +221,14 @@
190
221
  </select>
191
222
  </div>
192
223
 
224
+ <div class="form-row">
225
+ <div class="form-row">
226
+ <label for="node-input-config">
227
+ <i class="fa fa-cog"></i> Config
228
+ </label>
229
+ <input type="text" id="node-input-config" />
230
+ </div>
231
+
193
232
  <div class="form-row">
194
233
  <label for="node-input-area">
195
234
  <i class="fa fa-map-marker"></i> Area
@@ -244,7 +283,7 @@
244
283
  <i class="fa fa-exchange"></i> Subscribe topic
245
284
  </label>
246
285
  <input type="text" id="node-input-subscribeTopic"
247
- placeholder="e.g. MW3D/Master/PIR_Sensors"
286
+ placeholder="Required — e.g. home/Master/PIR_Sensors"
248
287
  style="width:55%" />
249
288
  </div>
250
289
 
@@ -19,6 +19,22 @@ module.exports = function (RED) {
19
19
 
20
20
  broker.register(node);
21
21
 
22
+ // ── Broker connection feedback ────────────────────────────────
23
+ setStatus('yellow', 'ring', 'Connecting to broker...');
24
+ 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');
33
+ });
34
+
35
+ // ── Discovery mode ─────────────────────────────────────────
36
+ const discoveryMode = config.discoveryMode || 'enabled';
37
+
22
38
  // ── Node settings ─────────────────────────────────────────
23
39
  const S = {
24
40
  uid: config.uid || '',
@@ -8,7 +8,7 @@
8
8
 
9
9
  RED.nodes.registerType('ha-mqtt-relay', {
10
10
  category: 'DMX for HA',
11
- color: '#e67e22',
11
+ color: '#e74c3c',
12
12
  icon: 'font-awesome/fa-toggle-on',
13
13
  inputs: 1,
14
14
  outputs: 0,
@@ -17,6 +17,7 @@
17
17
 
18
18
  defaults: {
19
19
  name: { value: '' },
20
+ discoveryMode: { value: 'enabled' },
20
21
  config: { value: '', type: 'ha-mqtt-config', required: true },
21
22
  // Fixture identity
22
23
  uidPrefix: { value: 'P', required: true },
@@ -143,13 +144,23 @@
143
144
  placeholder="Optional — defaults to fixture ID e.g. P-51" />
144
145
  </div>
145
146
 
147
+ <!-- Discovery Mode -->
146
148
  <div class="form-row">
147
- <label for="node-input-config">
148
- <i class="fa fa-cog"></i> Config
149
+ <label for="node-input-discoveryMode">
150
+ <i class="fa fa-toggle-on"></i> Discovery Mode
149
151
  </label>
150
- <input type="text" id="node-input-config" />
152
+ <select id="node-input-discoveryMode" style="width:55%">
153
+ <option value="enabled">Enabled — discovered and visible in HA</option>
154
+ <option value="hidden">Hidden — discovered but hidden in HA dashboard</option>
155
+ <option value="disabled">Disabled — not discovered, not in HA</option>
156
+ </select>
157
+ <div style="margin-left:106px; margin-top:4px; color:#999; font-size:0.85em;">
158
+ Use <strong>Disabled</strong> for future fixtures not yet wired.
159
+ Use <strong>Hidden</strong> for fixtures installed but not ready for the homeowner.
160
+ </div>
151
161
  </div>
152
162
 
163
+
153
164
  <hr/>
154
165
 
155
166
  <!-- ── RELAY (* Required) ────────────────────────────────── -->
@@ -180,18 +191,46 @@
180
191
  <input type="text" id="node-input-uid"
181
192
  placeholder="51" style="width:70px" />
182
193
  &nbsp;
183
- <select id="node-input-uidPostfix" style="width:65px">
194
+ <select id="node-input-uidPostfix" style="width:90px">
184
195
  <option value="">(none)</option>
185
196
  <option value="-A">-A</option>
186
197
  <option value="-B">-B</option>
187
198
  <option value="-C">-C</option>
188
199
  <option value="-D">-D</option>
200
+ <option value="-E">-E</option>
201
+ <option value="-F">-F</option>
202
+ <option value="-G">-G</option>
203
+ <option value="-H">-H</option>
204
+ <option value="-J">-J</option>
205
+ <option value="-K">-K</option>
206
+ <option value="-L">-L</option>
207
+ <option value="-M">-M</option>
208
+ <option value="-N">-N</option>
209
+ <option value="-P">-P</option>
210
+ <option value="-Q">-Q</option>
211
+ <option value="-R">-R</option>
212
+ <option value="-S">-S</option>
213
+ <option value="-T">-T</option>
214
+ <option value="-U">-U</option>
215
+ <option value="-V">-V</option>
216
+ <option value="-W">-W</option>
217
+ <option value="-X">-X</option>
218
+ <option value="-Y">-Y</option>
219
+ <option value="-Z">-Z</option>
189
220
  </select>
190
221
  <span style="margin-left:8px; color:#999; font-size:0.85em;">
191
- Prefix — Plan ID — Channel
222
+ Prefix — Plan ID — Postfix
192
223
  </span>
193
224
  </div>
194
225
 
226
+ <div class="form-row">
227
+ <div class="form-row">
228
+ <label for="node-input-config">
229
+ <i class="fa fa-cog"></i> Config
230
+ </label>
231
+ <input type="text" id="node-input-config" />
232
+ </div>
233
+
195
234
  <div class="form-row">
196
235
  <label for="node-input-area">
197
236
  <i class="fa fa-map-marker"></i> Area
@@ -22,6 +22,22 @@ module.exports = function (RED) {
22
22
 
23
23
  broker.register(node);
24
24
 
25
+ // ── Broker connection feedback ────────────────────────────────
26
+ setStatus('yellow', 'ring', 'Connecting to broker...');
27
+ 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');
36
+ });
37
+
38
+ // ── Discovery mode ─────────────────────────────────────────
39
+ const discoveryMode = config.discoveryMode || 'enabled';
40
+
25
41
  // ── Node settings ─────────────────────────────────────────
26
42
  const S = {
27
43
  uidPrefix: config.uidPrefix || 'P',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-dmx-for-ha",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
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",
@@ -25,15 +25,15 @@
25
25
  "node-red": {
26
26
  "version": ">=3.0.0",
27
27
  "nodes": {
28
- "ha-mqtt-config": "nodes/ha-mqtt-config.js",
29
- "ha-mqtt-dmx": "nodes/ha-mqtt-dmx.js",
30
- "ha-mqtt-dmx-group": "nodes/ha-mqtt-dmx-group.js",
31
- "ha-mqtt-relay": "nodes/ha-mqtt-relay.js",
32
- "ha-mqtt-button": "nodes/ha-mqtt-button.js",
33
- "ha-mqtt-pir": "nodes/ha-mqtt-pir.js"
28
+ "ha-mqtt-config": "nodes/ha-mqtt-config.js",
29
+ "ha-mqtt-dmx": "nodes/ha-mqtt-dmx.js",
30
+ "ha-mqtt-dmx-group": "nodes/ha-mqtt-dmx-group.js",
31
+ "ha-mqtt-relay": "nodes/ha-mqtt-relay.js",
32
+ "ha-mqtt-button": "nodes/ha-mqtt-button.js",
33
+ "ha-mqtt-pir": "nodes/ha-mqtt-pir.js"
34
34
  }
35
35
  },
36
36
  "engines": {
37
37
  "node": ">=18.0.0"
38
38
  }
39
- }
39
+ }