node-red-contrib-dmx-for-ha 0.1.0

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 ADDED
@@ -0,0 +1,282 @@
1
+ # node-red-contrib-dmx-for-ha
2
+
3
+ DMX lighting control for Home Assistant via Node-RED and MQTT.
4
+
5
+ Place a node, fill in the settings, deploy. Your DMX fixture appears in Home Assistant automatically — ready to use in automations, dashboards, and scenes.
6
+
7
+ No YAML. No custom MQTT discovery config. No external wiring inside Node-RED.
8
+
9
+ ---
10
+
11
+ ## What this package does
12
+
13
+ Bridges the gap between DMX lighting hardware and Home Assistant.
14
+
15
+ Most DMX implementations require either expensive proprietary hardware or complex custom integrations. This package gives you a drop-in Node-RED node that handles everything:
16
+
17
+ - Full Home Assistant MQTT discovery — entities appear automatically in HA
18
+ - RGBW, RGBWW, RGB, Colour Temperature, Brightness, and On/Off colour modes
19
+ - Gamma-corrected DMX output
20
+ - Transitions, effects, and group control
21
+ - State persistence across reboots
22
+ - Wall button and PIR motion sensor integration
23
+
24
+ > **Note:** This is building automation DMX — fixtures, decoders, dimmers, relay switching. Not entertainment industry DMX (no movers, gobos, or fixture profiles). DMX is an open standard and this package works with any DMX controller that accepts MQTT payloads.
25
+
26
+ ---
27
+
28
+ ## Nodes included
29
+
30
+ | Node | Palette label | Purpose |
31
+ |---|---|---|
32
+ | `ha-mqtt-config` | *(config)* | Shared site config — broker, zone, HA settings |
33
+ | `ha-mqtt-dmx` | DMX | Single DMX fixture |
34
+ | `ha-mqtt-dmx-group` | DMX Group | Virtual group — fans commands to child nodes |
35
+ | `ha-mqtt-relay` | Relay | 230V relay switching (not DMX) |
36
+ | `ha-mqtt-button` | Button | Wall button receiver |
37
+ | `ha-mqtt-pir` | PIR | Motion sensor receiver |
38
+
39
+ ---
40
+
41
+ ## Requirements
42
+
43
+ - **Node-RED** 3.0.0 or later
44
+ - **Home Assistant** with MQTT integration configured
45
+ - **Mosquitto** (or any MQTT broker) accessible from Node-RED
46
+ - **Node.js** 18.0.0 or later
47
+
48
+ ---
49
+
50
+ ## Installation
51
+
52
+ ```bash
53
+ cd ~/.node-red
54
+ npm install node-red-contrib-dmx-for-ha
55
+ ```
56
+
57
+ Restart Node-RED. The nodes appear in the palette under **DMX for HA**.
58
+
59
+ ---
60
+
61
+ ## ⚠️ Required: Configure Node-RED context storage
62
+
63
+ This package stores fixture state (brightness, colour, on/off) so it survives Node-RED restarts. This requires a **disk context store** to be configured in Node-RED.
64
+
65
+ **Without this, fixture state resets to default every time Node-RED restarts.**
66
+
67
+ ### What this means
68
+
69
+ Node-RED has a context store — a key/value store for saving data. By default it only stores in memory (lost on restart). To persist across restarts you need to add a disk-backed store.
70
+
71
+ ### How to configure it
72
+
73
+ 1. Find your Node-RED `settings.js` file. Location depends on your setup:
74
+ - Home Assistant add-on: `/config/node-red/settings.js`
75
+ - Standard install: `~/.node-red/settings.js`
76
+
77
+ 2. Find the `contextStorage` section (it may be commented out) and update it:
78
+
79
+ ```javascript
80
+ contextStorage: {
81
+ default: {
82
+ module: "memory"
83
+ },
84
+ disk: {
85
+ module: "localfilesystem"
86
+ }
87
+ },
88
+ ```
89
+
90
+ 3. Restart Node-RED.
91
+
92
+ ### How to check it is working
93
+
94
+ After restarting, open Node-RED → Menu → Context Data. You should see both `memory` and `disk` listed as available stores.
95
+
96
+ If you only see `default` or `memory`, the disk store is not configured correctly.
97
+
98
+ ### What happens without it
99
+
100
+ The nodes will still work — they fall back to memory storage gracefully. But:
101
+ - All fixture states reset to their default (usually OFF) every time Node-RED restarts
102
+ - Physical relays may not be re-asserted correctly after a reboot
103
+ - DMX channels may not restore to their previous values
104
+
105
+ For a production deployment, disk context storage is essential.
106
+
107
+ ---
108
+
109
+ ## Quick start
110
+
111
+ ### 1. Create a config node
112
+
113
+ Every node needs a config node. You create it once per zone.
114
+
115
+ 1. Drag a **DMX** node onto the canvas
116
+ 2. Open its editor and click the pencil icon next to **Config**
117
+ 3. Fill in:
118
+ - **Name** — e.g. `Master Zone`
119
+ - **Site ID** — a short slug for your MQTT topics, e.g. `home` (no spaces)
120
+ - **Zone** — e.g. `Master` (no spaces or special characters)
121
+ - **Broker** — select your existing MQTT broker config
122
+ 4. Click **Add** — the config is saved and shared across all nodes
123
+
124
+ ### 2. Add a DMX fixture
125
+
126
+ 1. Drag a **DMX** node onto the canvas
127
+ 2. Select your **Config** node
128
+ 3. Choose **Colour Mode** — RGBW, RGB, CCT etc.
129
+ 4. Set **Fixture ID** — Prefix (`L`), Plan ID number, optional channel letter
130
+ 5. Enter the **DMX channels** for this fixture
131
+ 6. Set the **Controller** and **Universe** numbers
132
+ 7. Deploy
133
+
134
+ Your fixture appears in Home Assistant automatically under **Settings → Devices**.
135
+
136
+ ### 3. Wire the SYSTEM node
137
+
138
+ The SYSTEM node sends `device:add` on startup so nodes register with HA.
139
+ Wire an inject node (set to fire on deploy + every X seconds) with:
140
+
141
+ ```
142
+ msg.device = "add"
143
+ ```
144
+
145
+ Wire it to the input of every node on your canvas.
146
+
147
+ ---
148
+
149
+ ## Multi-zone deployments
150
+
151
+ Create one `ha-mqtt-config` node per zone:
152
+
153
+ - `Master Zone` → Site ID: `home`, Zone: `Master`
154
+ - `Guest Wing` → Site ID: `home`, Zone: `GuestWing`
155
+
156
+ Each DMX, Relay, Button and PIR node picks its zone via the Config dropdown.
157
+ MQTT topics are built automatically: `{siteId}/{zone}/dmx/{universe}`.
158
+
159
+ ---
160
+
161
+ ## DMX Group Node
162
+
163
+ The DMX Group node appears as a single light entity in HA. Commands sent to it
164
+ are forwarded to all nodes connected to its **Link** output.
165
+
166
+ ```
167
+ [DMX Group LG-992]
168
+ │ Link
169
+ ├──→ [DMX L-992-A]
170
+ ├──→ [DMX L-992-B]
171
+ └──→ [DMX L-992-C]
172
+ ```
173
+
174
+ Wire the **Link** output to the input of each child DMX or Relay node.
175
+ You can also wire it to another DMX Group node for nested hierarchies.
176
+
177
+ ---
178
+
179
+ ## Wall buttons
180
+
181
+ The Button node creates two HA entities per button:
182
+
183
+ - `binary_sensor.s_10_a` — automation trigger, auto-clears after hold time
184
+ - `button.s_10_a_btn` — dashboard UI mirror (press from HA frontend)
185
+
186
+ Build your automations using the `binary_sensor` entity. The `button` entity
187
+ lets you test automations from the HA dashboard without physically pressing the wall button.
188
+
189
+ ---
190
+
191
+ ## PIR sensors
192
+
193
+ The PIR node goes **offline** in HA for a configurable warm-up period after
194
+ Node-RED starts. HA ignores all motion triggers during this time.
195
+
196
+ This prevents spurious motion events during controller reboot from triggering
197
+ lights in the middle of the night.
198
+
199
+ Set the warm-up time to match your PIR hardware's stabilisation period (default 120s).
200
+
201
+ ---
202
+
203
+ ## MQTT topic formats
204
+
205
+ | Node | Topic |
206
+ |---|---|
207
+ | DMX | `{siteId}/{zone}/dmx/{universe}` |
208
+ | Relay controller | `{siteId}/{zone}/{controller}/relay/{relayNum}` |
209
+ | HA discovery | `homeassistant/light/{fixtureId}/config` |
210
+ | HA state | `homeassistant/light/{fixtureId}/state` |
211
+ | HA command | `homeassistant/light/{fixtureId}/cmd` |
212
+
213
+ ---
214
+
215
+ ## DMX output format
216
+
217
+ DMX values are published as a 6-character string:
218
+
219
+ ```
220
+ "212255" → channel 212, value 255
221
+ "201000" → channel 201, value 0
222
+ ```
223
+
224
+ Three digits for channel, three digits for value. Your DMX controller firmware
225
+ must expect this format.
226
+
227
+ ---
228
+
229
+ ## Fixture ID conventions
230
+
231
+ Fixture IDs match your electrical plan cable IDs:
232
+
233
+ | Prefix | Meaning | Example |
234
+ |---|---|---|
235
+ | `L` | Light (DMX) | `L-992-A` |
236
+ | `P` | Power (Relay) | `P-51` |
237
+ | `LG` | Light Group (DMX Group) | `LG-992` |
238
+ | `S` | Sensor (Button / PIR) | `S-10-A` |
239
+
240
+ The channel letter (`-A`, `-B`, `-C`, `-D`) identifies individual channels
241
+ within a multi-channel cable. `L-992-A`, `L-992-B`, `L-992-C` are three
242
+ separate fixtures on cable 992, grouped under `LG-992`.
243
+
244
+ ---
245
+
246
+ ## Troubleshooting
247
+
248
+ **Nodes don't appear in palette**
249
+ Restart Node-RED. Check the NR log for install errors.
250
+
251
+ **Fixture doesn't appear in HA**
252
+ - Check the MQTT broker connection in the config node
253
+ - Confirm HA has the MQTT integration installed and configured
254
+ - Send a `device:add` message manually via an inject node
255
+ - Check Node-RED logs for error messages
256
+
257
+ **State resets on restart**
258
+ Configure disk context storage — see the [Required setup](#️-required-configure-node-red-context-storage) section above.
259
+
260
+ **PIR stuck offline**
261
+ The warm-up timer is running. Wait for the configured warm-up period.
262
+ Or send `msg.device = "avty"` with `msg.payload = "online"` to bring it online manually.
263
+
264
+ **Relay not switching**
265
+ - Check the relay MQTT topic in the NR debug panel
266
+ - Confirm your relay controller subscribes to `{siteId}/{zone}/{controller}/relay/{relayNum}`
267
+ - Relay payload is `"1"` (ON) or `"0"` (OFF) as a string
268
+
269
+ **DMX channels not responding**
270
+ - Verify DMX channel numbers match your fixture's start address
271
+ - Check the DMX MQTT topic in the NR debug panel
272
+ - Confirm your DMX controller subscribes to `{siteId}/{zone}/dmx/{universe}`
273
+
274
+ ---
275
+
276
+ ## Author
277
+
278
+ DeSwaggy — Discord: @deswaggy
279
+
280
+ ## License
281
+
282
+ Apache-2.0
@@ -0,0 +1,236 @@
1
+ # ha-mqtt-config — Config Node Specification
2
+ **Status:** Pre-packaging design spec
3
+ **Purpose:** Defines what moves to the shared config node vs stays per-node
4
+
5
+ ---
6
+
7
+ ## The Config Node: `ha-mqtt-config`
8
+
9
+ Created once per site (or per zone). Referenced by all other nodes via dropdown.
10
+ Replaces all site-wide repeated fields that were previously entered on every node.
11
+
12
+ ---
13
+
14
+ ## Config Node Fields
15
+
16
+ ### SITE
17
+ | Field | Env var replaced | Notes |
18
+ |---|---|---|
19
+ | Site ID | `<HA_site_unique_id>` | e.g. `home`, `unit4`, `smithresidence` — used in MQTT topic construction |
20
+ | MQTT Broker | (broker config node) | Dropdown picks existing NR MQTT broker config |
21
+
22
+ ### HA MQTT
23
+ | Field | Env var replaced | Notes |
24
+ |---|---|---|
25
+ | Discovery prefix | `<HA_discovery_prefix>` | Default `homeassistant` — rarely changes |
26
+ | QoS | `<HA_MQTT_QOS>` | Default `0` |
27
+ | Retain | `<HA_MQTT_retain_flag>` | Default `false` |
28
+ | Config topic | `<HA_config_topic>` | Default `config` |
29
+ | State topic | `<HA_state_topic>` | Default `state` |
30
+ | Command topic | `<HA_command_topic>` | Default `cmd` |
31
+ | Availability topic | `<HA_availability_topic>` | Default `avty` — PIR only but lives here |
32
+
33
+ ### DEFAULTS (site-wide)
34
+ | Field | Env var replaced | Notes |
35
+ |---|---|---|
36
+ | Enabled by default | `<HA_enabled_by_default>` | Default `true` — applies to all nodes |
37
+ | Disk save delay (s) | `<CONTEXT_STORE_values_to_disk_delay_in_seconds>` | Default `10` |
38
+ | Flash Short (s) | `<HA_effects_flash_time_Short_(seconds)>` | Default `1` |
39
+ | Flash Long (s) | `<HA_effects_flash_time_Long_(seconds)>` | Default `10` |
40
+
41
+ ---
42
+
43
+ ## What Stays Per-Node
44
+
45
+ Everything fixture-specific stays on the individual node editor panel.
46
+ Dramatically shorter menus as a result.
47
+
48
+ ### ha-mqtt-dmx
49
+ ```
50
+ FIXTURE (* Required)
51
+ Config: [ My Home ▼ ] ← config node picker
52
+ Colour Mode: [ RGBW ▼ ]
53
+ Device Type: [ Downlight ▼ ]
54
+ Prefix: [ L ▼ ] ID: [992] Postfix: [ -A ▼ ]
55
+ Area: [ Bedroom 1 ▼ ]
56
+ Situation: [ in ▼ ]
57
+ Sub-Area: [ Bed (North) ▼ ]
58
+
59
+ DMX CHANNELS
60
+ Red: [201] Green: [202]
61
+ Blue: [203] White: [204] Warm White: [205]
62
+
63
+ DMX CONTROLLER
64
+ Controller: [1] Universe: [1]
65
+
66
+ OPTIONS
67
+ HA Icon: [mdi:lightbulb]
68
+ Show effects ☑
69
+ Enable transitions ☑
70
+ Sync via Group ☐
71
+ Default state: [ OFF ▼ ]
72
+
73
+ ADVANCED
74
+ DMX limiter: [255]
75
+ Min output: [1]
76
+ Brightness bump: [212]
77
+ Transition ticks: [31]
78
+ ```
79
+
80
+ ### ha-mqtt-dmx-group
81
+ ```
82
+ GROUP (* Required)
83
+ Config: [ My Home ▼ ]
84
+ Group Name: [Bedroom 1 Downlights]
85
+ Group ID: [992] Postfix: [ (none) ▼ ]
86
+ Device Type: [ Downlight ▼ ]
87
+ Colour Mode: [ RGBW ▼ ]
88
+ Area: [ Bedroom 1 ▼ ]
89
+ Situation: [ in ▼ ]
90
+ Sub-Area: [ (none) ▼ ]
91
+
92
+ OPTIONS
93
+ HA Icon: [mdi:lightbulb-group]
94
+ Show effects ☑
95
+ Enable transitions ☑
96
+ Default state: [ OFF ▼ ]
97
+
98
+ ADVANCED
99
+ Max group depth: [10]
100
+ ```
101
+
102
+ ### ha-mqtt-relay
103
+ ```
104
+ RELAY (* Required)
105
+ Config: [ My Home ▼ ]
106
+ Device Type: [ Exhaust Fan ▼ ]
107
+ Prefix: [ P ▼ ] ID: [51] Postfix: [ (none) ▼ ]
108
+ Area: [ Bathroom ▼ ]
109
+ Situation: [ in ▼ ]
110
+ Sub-Area: [ (none) ▼ ]
111
+
112
+ CONTROLLER
113
+ Controller: [15] Relay: [25]
114
+ MQTT segment: [relay]
115
+
116
+ OPTIONS
117
+ HA Icon: [mdi:fan]
118
+ Show effects ☑
119
+ Default state: [ OFF ▼ ]
120
+ ```
121
+
122
+ ### ha-mqtt-button
123
+ ```
124
+ BUTTON (* Required)
125
+ Config: [ My Home ▼ ]
126
+ Cable ID: [10] Letter: [ -A ▼ ]
127
+ Area: [ Bedroom 1 ▼ ]
128
+ Situation: [ in ▼ ]
129
+ Sub-Area: [ Bed (North) ▼ ]
130
+ Position: [ Top Left ▼ ]
131
+
132
+ CONTROLLER
133
+ Payload (panelId-GPIOpin): [10-54]
134
+ Subscribe topic: [buttons]
135
+
136
+ OPTIONS
137
+ HA Icon: [mdi:gesture-tap-button]
138
+ LED Colour: [ Blue ▼ ]
139
+ Hold time (s): [0.5]
140
+ ```
141
+
142
+ ### ha-mqtt-pir
143
+ ```
144
+ PIR (* Required)
145
+ Config: [ My Home ▼ ]
146
+ Cable ID: [31] Sensor Group: [ (none) ▼ ]
147
+ Area: [ Bedroom 1 ▼ ]
148
+ Situation: [ in ▼ ]
149
+ Sub-Area: [ Ceiling ▼ ]
150
+ PIR Type: [ Ceiling ▼ ]
151
+
152
+ CONTROLLER
153
+ Payload (panelId-GPIOpin): [13-62]
154
+ Subscribe topic: [MW3D/Master/PIR_Sensors]
155
+
156
+ OPTIONS
157
+ HA Icon: [mdi:motion-sensor]
158
+ Cable Colour: [ Purple ▼ ]
159
+ Hold time (s): [15]
160
+ Warm-up time (s): [120]
161
+ ```
162
+
163
+ ---
164
+
165
+ ## Fields Removed From Per-Node (now in config)
166
+
167
+ These fields disappear entirely from individual node editors:
168
+
169
+ | Field | Was in |
170
+ |---|---|
171
+ | `<HA_site_unique_id>` | DMX, DMX Group, Relay, Button, PIR |
172
+ | `<HA_discovery_prefix>` | DMX, DMX Group, Relay, Button, PIR |
173
+ | `<HA_MQTT_QOS>` | DMX, DMX Group, Relay, Button, PIR |
174
+ | `<HA_MQTT_retain_flag>` | DMX, DMX Group, Relay, Button, PIR |
175
+ | `<HA_config_topic>` | DMX, DMX Group, Relay, Button, PIR |
176
+ | `<HA_state_topic>` | DMX, DMX Group, Relay, Button, PIR |
177
+ | `<HA_command_topic>` | DMX, DMX Group, Relay, Button, PIR |
178
+ | `<HA_availability_topic>` | PIR |
179
+ | `<HA_enabled_by_default>` | DMX, DMX Group, Relay, Button, PIR |
180
+ | `<CONTEXT_STORE_values_to_disk_delay_in_seconds>` | DMX, DMX Group, Relay |
181
+ | `<HA_effects_flash_time_Short_(seconds)>` | DMX, DMX Group, Relay |
182
+ | `<HA_effects_flash_time_Long_(seconds)>` | DMX, DMX Group, Relay |
183
+
184
+ **12 fields removed from every node.** For a deployment with 50 DMX nodes,
185
+ 10 relays, 20 buttons, 10 PIRs — that's 90 × 12 = 1,080 fields the user
186
+ never has to touch.
187
+
188
+ ---
189
+
190
+ ## Zone Decision
191
+
192
+ Zone (`<CONTROLLER_zone>`) could go in the config node OR stay per-node.
193
+
194
+ **Arguments for config node:**
195
+ - Most deployments are single-zone (`Master`)
196
+ - If all nodes are in the same zone, enter it once
197
+
198
+ **Arguments for per-node:**
199
+ - Multi-zone deployments (Master + Guest Wing) need per-node zone selection
200
+ - A user might have two config nodes — one per zone — which also works
201
+
202
+ **Recommendation:** Keep Zone in config node, allow multiple config nodes
203
+ for multi-zone deployments. A user with Master + Guest Wing creates:
204
+ - `ha-mqtt-config` named "Master Zone" with zone=Master
205
+ - `ha-mqtt-config` named "Guest Wing" with zone=GuestWing
206
+
207
+ Each node then picks the right config from the dropdown.
208
+ This is cleaner than per-node zone selection.
209
+
210
+ ---
211
+
212
+ ## Relay-Specific MQTT Settings
213
+
214
+ The relay node currently has separate QoS/retain for the relay controller
215
+ (separate from the HA-side MQTT settings). In the config node:
216
+
217
+ - HA MQTT settings → main config node settings
218
+ - Relay controller MQTT → either same config node with "Relay" section,
219
+ OR per-node (since relay controllers may differ from HA broker)
220
+
221
+ **Recommendation:** Keep relay controller QoS/retain per-node under
222
+ CONTROLLER section. It's controller-hardware specific, not site-wide.
223
+
224
+ ---
225
+
226
+ ## Pre-packaging Checklist Update
227
+
228
+ - [x] Config node concept agreed
229
+ - [x] Config node fields defined
230
+ - [x] Per-node fields defined (trimmed menus)
231
+ - [x] Zone goes in config node (multi-zone = multiple config nodes)
232
+ - [ ] Config node name finalised: `ha-mqtt-config`
233
+ - [ ] Agree on relay controller MQTT settings (per-node recommended)
234
+ - [ ] Write config node .html editor file (first, before any other node)
235
+ - [ ] Write config node .js runtime file
236
+ - [ ] Then write ha-mqtt-dmx .html (references config node)