node-red-contrib-dmx-for-ha 0.3.9 → 0.4.3

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.
@@ -236,6 +236,15 @@ module.exports = function (RED) {
236
236
  });
237
237
  }
238
238
 
239
+
240
+ function groupStatus(state, label) {
241
+ if (state === 'ON') {
242
+ setStatus('green', 'dot', label || `${groupId} ON`);
243
+ } else {
244
+ setStatus('grey', 'ring', label || `${groupId} OFF`);
245
+ }
246
+ }
247
+
239
248
  // ── Device add ────────────────────────────────────────────
240
249
  function handleDeviceAdd(incomingTrace) {
241
250
  if (!ctxGet('state') && !ctxGet('state', 'disk_values')) {
@@ -281,10 +290,10 @@ module.exports = function (RED) {
281
290
  catch(e) { node.warn(`${groupId} — failed to parse HA command`); return; }
282
291
 
283
292
  saveGroupState(payload);
284
- pubState({ state: payload.state, color_mode: S.colorMode, brightness: payload.brightness });
293
+ pubState({ state: payload.state, color_mode: S.colorMode, brightness: payload.brightness, color: payload.color });
285
294
  forwardToChildren(payload, null);
286
295
  const _lbl = payload.effect ? `effect:${payload.effect}` : `${payload.state}`;
287
- setStatus('green', 'dot', `${groupId} → ${_lbl}`);
296
+ groupStatus(payload.state, `${groupId} → ${_lbl}`);
288
297
  }, node.id);
289
298
 
290
299
  setStatus('green', 'ring', `${groupId} discovery sent`);
@@ -297,8 +306,10 @@ module.exports = function (RED) {
297
306
  const brightness = recall('brightness', 'brightness_disk', 255);
298
307
  const color = recall('color', 'color_disk', null);
299
308
  pubState({ state, color_mode: S.colorMode, brightness, color });
300
- forwardToChildren({ state, brightness, color }, null);
301
- setStatus('yellow', 'ring', `${groupId} ready`);
309
+ // NOTE: do NOT forward to children on recovery — each child node
310
+ // recovers its own state independently from its own disk store.
311
+ // Forwarding here would overwrite children with the group's state.
312
+ groupStatus(state, `${groupId} → ${state}`);
302
313
  node.log(`${groupId} recovery — state:${state}`);
303
314
  }, 2000);
304
315
  }
@@ -306,7 +317,9 @@ module.exports = function (RED) {
306
317
  // ── Device remove ─────────────────────────────────────────
307
318
  function handleDeviceRemove(incomingTrace) {
308
319
  if (diskTimer) { clearTimeout(diskTimer); diskTimer = null; }
309
- ctxSet('state', null); ctxSet('state', null, 'disk_values');
320
+ // No flush needed on remove — state is cleared below
321
+ // Keep disk state on remove — state survives remove/add cycles
322
+ ctxSet('state', null); // RAM only
310
323
  pub(cfgTopic, '', true);
311
324
  broker.unsubscribe(cmdTopic, node.id);
312
325
  forwardToChildren({ device: 'remove' }, incomingTrace);
@@ -325,9 +338,9 @@ module.exports = function (RED) {
325
338
  // Forward payload deeper
326
339
  if (msg.payload) {
327
340
  saveGroupState(msg.payload);
328
- pubState({ state: msg.payload.state, color_mode: S.colorMode, brightness: msg.payload.brightness });
341
+ pubState({ state: msg.payload.state, color_mode: S.colorMode, brightness: msg.payload.brightness, color: msg.payload.color });
329
342
  forwardToChildren(msg.payload, msg.dmx_trace);
330
- setStatus('green', 'dot', `${groupId} → cascade:${msg.payload.state}`);
343
+ groupStatus(msg.payload.state, `${groupId} → cascade:${msg.payload.state}`);
331
344
  }
332
345
  } else {
333
346
  const devReq = typeof msg.device === 'string'
@@ -342,9 +355,9 @@ module.exports = function (RED) {
342
355
  }
343
356
  } else if (msg.payload && msg.payload.state != null) {
344
357
  saveGroupState(msg.payload);
345
- pubState({ state: msg.payload.state, color_mode: S.colorMode, brightness: msg.payload.brightness });
358
+ pubState({ state: msg.payload.state, color_mode: S.colorMode, brightness: msg.payload.brightness, color: msg.payload.color });
346
359
  forwardToChildren(msg.payload, null);
347
- setStatus('green', 'dot', `${groupId} → ${msg.payload.state}`);
360
+ groupStatus(msg.payload.state, `${groupId} → ${msg.payload.state}`);
348
361
  } else {
349
362
  node.warn(`${groupId} — unrecognised message received and dropped. See node documentation.`);
350
363
  }
@@ -693,8 +693,10 @@ module.exports = function (RED) {
693
693
  ctxSet('warmWhite',ww,'disk_values');
694
694
  }
695
695
  }
696
+ // Keep disk state on remove — state survives remove/add cycles
697
+ // Only clear RAM so recovery on re-add reads last known disk state
696
698
  ['state','brightness','red','green','blue','white','warmWhite'].forEach(function (k) {
697
- ctxSet(k, null); ctxSet(k, null, 'disk_values');
699
+ ctxSet(k, null);
698
700
  });
699
701
  pub(cfgTopic, '', true);
700
702
  broker.unsubscribe(cmdTopic, node.id);
@@ -332,7 +332,8 @@ module.exports = function (RED) {
332
332
  function handleDeviceRemove() {
333
333
  stopEffect();
334
334
  if (diskTimer) { clearTimeout(diskTimer); diskTimer = null; }
335
- ctxSet('state', null); ctxSet('state', null, 'disk_values');
335
+ // Keep disk state on remove — state survives remove/add cycles
336
+ ctxSet('state', null); // RAM only
336
337
  pub(cfgTopic, '', true);
337
338
  broker.unsubscribe(cmdTopic, node.id);
338
339
  setStatus('red', 'ring', `${fixtureId} removed`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-dmx-for-ha",
3
- "version": "0.3.9",
3
+ "version": "0.4.3",
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",