node-red-contrib-dmx-for-ha 0.4.1 → 0.4.4
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 +121 -0
- package/nodes/ha-mqtt-dmx-group.js +5 -4
- package/nodes/ha-mqtt-dmx.js +8 -2
- package/nodes/ha-mqtt-relay.js +7 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -270,6 +270,127 @@ Set to `0` to make all un-timed commands instant.
|
|
|
270
270
|
|
|
271
271
|
---
|
|
272
272
|
|
|
273
|
+
## Context store — finding your files
|
|
274
|
+
|
|
275
|
+
This is one of the most common questions with Node-RED on Home Assistant. The context store files are **not** where you expect them.
|
|
276
|
+
|
|
277
|
+
### Where are the files?
|
|
278
|
+
|
|
279
|
+
The NR add-on runs in its own Docker container with an isolated config directory. This is **separate** from the main HA config you see via Samba.
|
|
280
|
+
|
|
281
|
+
| What you see | Actual path on host |
|
|
282
|
+
|---|---|
|
|
283
|
+
| Samba `\\{haip}\config\` | HA config — flows, automations etc. |
|
|
284
|
+
| NR add-on config | `/addon_configs/a0d7b954_nodered/` |
|
|
285
|
+
| Context store files | `/addon_configs/a0d7b954_nodered/nodeRED/context_stores/context/` |
|
|
286
|
+
|
|
287
|
+
The NR add-on config directory is **not accessible via Samba** — this trips everyone up.
|
|
288
|
+
|
|
289
|
+
### How to find your context files
|
|
290
|
+
|
|
291
|
+
Use the **Studio Code Server** add-on (VS Code in HA):
|
|
292
|
+
|
|
293
|
+
1. Install Studio Code Server from the add-on store if not already installed
|
|
294
|
+
2. Open it: Settings → Add-ons → Studio Code Server → Open Web UI
|
|
295
|
+
3. Open a terminal: Terminal → New Terminal
|
|
296
|
+
4. Run:
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
find / -name "*.json" -path "*context*" 2>/dev/null | grep -v proc
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
You should see something like:
|
|
303
|
+
```
|
|
304
|
+
/addon_configs/a0d7b954_nodered/nodeRED/context_stores/context/7e2467f26a0693a0/dd6582b967f0314a.json
|
|
305
|
+
/addon_configs/a0d7b954_nodered/nodeRED/context_stores/context/7e2467f26a0693a0/75b10249fcbfd224.json
|
|
306
|
+
...
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
One `.json` file per node, named by node ID.
|
|
310
|
+
|
|
311
|
+
### Reading a context file
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
cat "/addon_configs/a0d7b954_nodered/nodeRED/context_stores/context/{flowId}/{nodeId}.json"
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
A healthy file looks like:
|
|
318
|
+
```json
|
|
319
|
+
{
|
|
320
|
+
"state": "ON",
|
|
321
|
+
"brightness": 255,
|
|
322
|
+
"red": 255,
|
|
323
|
+
"green": 255,
|
|
324
|
+
"blue": 255,
|
|
325
|
+
"white": 255,
|
|
326
|
+
"warmWhite": 0
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Important: NR adds a `/context/` subfolder
|
|
331
|
+
|
|
332
|
+
When you set `dir` in your context store config, NR automatically appends `/context/` to it. So:
|
|
333
|
+
|
|
334
|
+
```javascript
|
|
335
|
+
// You set:
|
|
336
|
+
config: { dir: '/config/nodeRED/context_stores' }
|
|
337
|
+
|
|
338
|
+
// NR actually writes to:
|
|
339
|
+
// /config/nodeRED/context_stores/context/
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Recommended config.js settings
|
|
343
|
+
|
|
344
|
+
```javascript
|
|
345
|
+
contextStorage: {
|
|
346
|
+
memory: { module: 'memory' },
|
|
347
|
+
disk_values: {
|
|
348
|
+
module: 'localfilesystem',
|
|
349
|
+
config: {
|
|
350
|
+
dir: '/config/nodeRED/context_stores',
|
|
351
|
+
flushInterval: 5 // Write to disk every 5 seconds (default is 30)
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
disk_meta: {
|
|
355
|
+
module: 'localfilesystem',
|
|
356
|
+
config: {
|
|
357
|
+
dir: '/config/nodeRED/context_stores',
|
|
358
|
+
flushInterval: 5
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
default: { module: 'memory' },
|
|
362
|
+
},
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
**Important:** Use an **absolute path** starting with `/config/`. A relative path will silently resolve to the wrong location and nothing will be saved.
|
|
366
|
+
|
|
367
|
+
`flushInterval: 5` means NR writes to disk every 5 seconds instead of the default 30. This reduces the window of data loss on unexpected shutdown — after turning a light on, wait 5 seconds before restarting.
|
|
368
|
+
|
|
369
|
+
### Verifying context store is working
|
|
370
|
+
|
|
371
|
+
After saving a state and waiting 5+ seconds, check your files appeared:
|
|
372
|
+
|
|
373
|
+
```bash
|
|
374
|
+
ls "/addon_configs/a0d7b954_nodered/nodeRED/context_stores/context/"
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
If the directory is empty or doesn't exist — check your `config.js` path is absolute and restart NR.
|
|
378
|
+
|
|
379
|
+
### NR startup log confirmation
|
|
380
|
+
|
|
381
|
+
On every startup NR logs which context stores loaded:
|
|
382
|
+
|
|
383
|
+
```
|
|
384
|
+
Context store : 'memory' [module=memory]
|
|
385
|
+
Context store : 'disk_values' [module=localfilesystem]
|
|
386
|
+
Context store : 'disk_meta' [module=localfilesystem]
|
|
387
|
+
Context store : 'default' [module=memory]
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
If `disk_values` shows `[module=memory]` — your config.js change didn't take effect.
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
273
394
|
## Troubleshooting
|
|
274
395
|
|
|
275
396
|
**Nodes don't appear in palette** — Restart Node-RED. Check log for errors.
|
|
@@ -290,7 +290,7 @@ module.exports = function (RED) {
|
|
|
290
290
|
catch(e) { node.warn(`${groupId} — failed to parse HA command`); return; }
|
|
291
291
|
|
|
292
292
|
saveGroupState(payload);
|
|
293
|
-
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 });
|
|
294
294
|
forwardToChildren(payload, null);
|
|
295
295
|
const _lbl = payload.effect ? `effect:${payload.effect}` : `${payload.state}`;
|
|
296
296
|
groupStatus(payload.state, `${groupId} → ${_lbl}`);
|
|
@@ -318,7 +318,8 @@ module.exports = function (RED) {
|
|
|
318
318
|
function handleDeviceRemove(incomingTrace) {
|
|
319
319
|
if (diskTimer) { clearTimeout(diskTimer); diskTimer = null; }
|
|
320
320
|
// No flush needed on remove — state is cleared below
|
|
321
|
-
|
|
321
|
+
// Keep disk state on remove — state survives remove/add cycles
|
|
322
|
+
ctxSet('state', null); // RAM only
|
|
322
323
|
pub(cfgTopic, '', true);
|
|
323
324
|
broker.unsubscribe(cmdTopic, node.id);
|
|
324
325
|
forwardToChildren({ device: 'remove' }, incomingTrace);
|
|
@@ -337,7 +338,7 @@ module.exports = function (RED) {
|
|
|
337
338
|
// Forward payload deeper
|
|
338
339
|
if (msg.payload) {
|
|
339
340
|
saveGroupState(msg.payload);
|
|
340
|
-
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 });
|
|
341
342
|
forwardToChildren(msg.payload, msg.dmx_trace);
|
|
342
343
|
groupStatus(msg.payload.state, `${groupId} → cascade:${msg.payload.state}`);
|
|
343
344
|
}
|
|
@@ -354,7 +355,7 @@ module.exports = function (RED) {
|
|
|
354
355
|
}
|
|
355
356
|
} else if (msg.payload && msg.payload.state != null) {
|
|
356
357
|
saveGroupState(msg.payload);
|
|
357
|
-
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 });
|
|
358
359
|
forwardToChildren(msg.payload, null);
|
|
359
360
|
groupStatus(msg.payload.state, `${groupId} → ${msg.payload.state}`);
|
|
360
361
|
} else {
|
package/nodes/ha-mqtt-dmx.js
CHANGED
|
@@ -670,7 +670,11 @@ module.exports = function (RED) {
|
|
|
670
670
|
sendDmxChannels(buildColorChannels(0, r, g, b, w, ww));
|
|
671
671
|
}
|
|
672
672
|
pubState({ state, color_mode: S.colorMode, brightness, color: { r, g, b, w, ww } });
|
|
673
|
-
|
|
673
|
+
if (state === 'ON') {
|
|
674
|
+
setStatus('green', 'dot', `${fixtureId} ON bright:${brightness}`);
|
|
675
|
+
} else {
|
|
676
|
+
setStatus('grey', 'ring', `${fixtureId} OFF`);
|
|
677
|
+
}
|
|
674
678
|
node.log(`${fixtureId} recovery — state:${state}`);
|
|
675
679
|
}, 2000);
|
|
676
680
|
}
|
|
@@ -693,8 +697,10 @@ module.exports = function (RED) {
|
|
|
693
697
|
ctxSet('warmWhite',ww,'disk_values');
|
|
694
698
|
}
|
|
695
699
|
}
|
|
700
|
+
// Keep disk state on remove — state survives remove/add cycles
|
|
701
|
+
// Only clear RAM so recovery on re-add reads last known disk state
|
|
696
702
|
['state','brightness','red','green','blue','white','warmWhite'].forEach(function (k) {
|
|
697
|
-
ctxSet(k, null);
|
|
703
|
+
ctxSet(k, null);
|
|
698
704
|
});
|
|
699
705
|
pub(cfgTopic, '', true);
|
|
700
706
|
broker.unsubscribe(cmdTopic, node.id);
|
package/nodes/ha-mqtt-relay.js
CHANGED
|
@@ -323,7 +323,11 @@ module.exports = function (RED) {
|
|
|
323
323
|
const state = recall('state', 'state_disk', S.defaultState);
|
|
324
324
|
pubRelay(state === 'ON' ? 1 : 0);
|
|
325
325
|
pubState(state);
|
|
326
|
-
|
|
326
|
+
if (state === 'ON') {
|
|
327
|
+
setStatus('green', 'dot', `${fixtureId} ON`);
|
|
328
|
+
} else {
|
|
329
|
+
setStatus('grey', 'ring', `${fixtureId} OFF`);
|
|
330
|
+
}
|
|
327
331
|
node.log(`${fixtureId} recovery — state:${state}`);
|
|
328
332
|
}, 2000);
|
|
329
333
|
}
|
|
@@ -332,7 +336,8 @@ module.exports = function (RED) {
|
|
|
332
336
|
function handleDeviceRemove() {
|
|
333
337
|
stopEffect();
|
|
334
338
|
if (diskTimer) { clearTimeout(diskTimer); diskTimer = null; }
|
|
335
|
-
|
|
339
|
+
// Keep disk state on remove — state survives remove/add cycles
|
|
340
|
+
ctxSet('state', null); // RAM only
|
|
336
341
|
pub(cfgTopic, '', true);
|
|
337
342
|
broker.unsubscribe(cmdTopic, node.id);
|
|
338
343
|
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.4.
|
|
3
|
+
"version": "0.4.4",
|
|
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",
|