node-red-contrib-dmx-for-ha 0.1.8 → 0.2.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.
@@ -15,11 +15,14 @@
15
15
  inputLabels: ['Input'],
16
16
  button: {
17
17
  onclick: function() {
18
+ var self = this;
18
19
  $.ajax({
19
- url: 'ha-mqtt-button/' + this.id + '/add',
20
+ url: 'ha-mqtt-button/' + this.id + '/toggle',
20
21
  type: 'POST',
21
- success: function() { RED.notify('device:add sent','success'); },
22
- error: function() { RED.notify('Error check NR log','error'); }
22
+ success: function(resp) {
23
+ RED.notify('device:' + resp.action + ' sent', 'success');
24
+ },
25
+ error: function() { RED.notify('Error — check NR log', 'error'); }
23
26
  });
24
27
  }
25
28
  },
@@ -144,139 +147,88 @@
144
147
  <script type="text/html" data-template-name="ha-mqtt-button">
145
148
 
146
149
  <div class="form-row">
147
- <label for="node-input-name">
148
- <i class="fa fa-tag"></i> Name
149
- </label>
150
- <input type="text" id="node-input-name"
151
- placeholder="Optional — defaults to S-10-A on canvas" />
152
- </div>
153
-
154
- <!-- Discovery Mode -->
155
- <div class="form-row">
156
- <label for="node-input-discoveryMode">
157
- <i class="fa fa-toggle-on"></i> Discovery Mode
158
- </label>
159
- <select id="node-input-discoveryMode" style="width:55%">
160
- <option value="enabled">Enabled — discovered and visible in HA</option>
161
- <option value="hidden">Hidden — discovered but hidden in HA dashboard</option>
162
- <option value="disabled">Disabled — not discovered, not in HA</option>
163
- </select>
164
- <div style="margin-left:106px; margin-top:4px; color:#999; font-size:0.85em;">
165
- Use <strong>Disabled</strong> for future fixtures not yet wired.
166
- Use <strong>Hidden</strong> for fixtures installed but not ready for the homeowner.
167
- </div>
150
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
151
+ <input type="text" id="node-input-name" placeholder="Optional — defaults to S-10-A on canvas" />
168
152
  </div>
169
153
 
170
-
171
154
  <hr/>
172
155
 
173
- <!-- ── BUTTON (* Required) ───────────────────────────────── -->
174
156
  <div class="form-row">
175
157
  <label style="width:100%; font-weight:bold; color:#999; font-size:0.85em; text-transform:uppercase; letter-spacing:0.05em;">
176
158
  <i class="fa fa-hand-pointer-o"></i> Button &nbsp;<span style="color:#e74c3c">* Required</span>
177
159
  </label>
178
160
  </div>
179
161
 
162
+ <!-- 1. Cable ID -->
180
163
  <div class="form-row">
181
- <label for="node-input-uid">
182
- <i class="fa fa-tv"></i> Cable ID
183
- </label>
164
+ <label for="node-input-uid"><i class="fa fa-tv"></i> Cable ID</label>
184
165
  <span style="margin-right:4px; font-weight:bold;">S -</span>
185
- <input type="text" id="node-input-uid"
186
- placeholder="10" style="width:70px" />
166
+ <input type="text" id="node-input-uid" placeholder="10" style="width:70px" />
187
167
  &nbsp;
188
168
  <select id="node-input-uidPostfix" style="width:90px">
189
169
  <option value="">(none)</option>
190
- <option value="-A">-A</option>
191
- <option value="-B">-B</option>
192
- <option value="-C">-C</option>
193
- <option value="-D">-D</option>
194
- <option value="-E">-E</option>
195
- <option value="-F">-F</option>
196
- <option value="-G">-G</option>
197
- <option value="-H">-H</option>
198
- <option value="-J">-J</option>
199
- <option value="-K">-K</option>
200
- <option value="-L">-L</option>
201
- <option value="-M">-M</option>
202
- <option value="-N">-N</option>
203
- <option value="-P">-P</option>
204
- <option value="-Q">-Q</option>
205
- <option value="-R">-R</option>
206
- <option value="-S">-S</option>
207
- <option value="-T">-T</option>
208
- <option value="-U">-U</option>
209
- <option value="-V">-V</option>
210
- <option value="-W">-W</option>
211
- <option value="-X">-X</option>
212
- <option value="-Y">-Y</option>
213
- <option value="-Z">-Z</option>
170
+ <option value="-A">-A</option><option value="-B">-B</option><option value="-C">-C</option><option value="-D">-D</option>
171
+ <option value="-E">-E</option><option value="-F">-F</option><option value="-G">-G</option><option value="-H">-H</option>
172
+ <option value="-J">-J</option><option value="-K">-K</option><option value="-L">-L</option><option value="-M">-M</option>
173
+ <option value="-N">-N</option><option value="-P">-P</option><option value="-Q">-Q</option><option value="-R">-R</option>
174
+ <option value="-S">-S</option><option value="-T">-T</option><option value="-U">-U</option><option value="-V">-V</option>
175
+ <option value="-W">-W</option><option value="-X">-X</option><option value="-Y">-Y</option><option value="-Z">-Z</option>
214
176
  </select>
215
- <span style="margin-left:8px; color:#999; font-size:0.85em;">
216
- Plan ID — Button letter
217
- </span>
177
+ <span style="margin-left:8px; color:#999; font-size:0.85em;">Plan ID — Button letter</span>
218
178
  </div>
219
179
 
180
+ <!-- 2. Position -->
220
181
  <div class="form-row">
182
+ <label for="node-input-buttonPosition"><i class="fa fa-hand-pointer-o"></i> Position</label>
183
+ <select id="node-input-buttonPosition" style="width:55%">
184
+ <option value="Top Left">Top Left</option><option value="Top Right">Top Right</option>
185
+ <option value="Bottom Left">Bottom Left</option><option value="Bottom Right">Bottom Right</option>
186
+ <option value="Top">Top</option><option value="Bottom">Bottom</option>
187
+ <option value="Left">Left</option><option value="Right">Right</option>
188
+ <option value="Centre">Centre</option><option value="Single">Single</option>
189
+ </select>
190
+ </div>
221
191
 
192
+ <!-- 3. Situation -->
222
193
  <div class="form-row">
223
- <div class="form-row">
224
- <label for="node-input-config">
225
- <i class="fa fa-cog"></i> Config
226
- </label>
227
- <input type="text" id="node-input-config" />
194
+ <label for="node-input-situation"><i class="fa fa-compass"></i> Situation</label>
195
+ <select id="node-input-situation" style="width:55%">
196
+ <option value="in">in</option><option value="above">above</option><option value="below">below</option>
197
+ <option value="outside">outside</option><option value="throughout">throughout</option>
198
+ <option value="under">under</option><option value="over">over</option>
199
+ </select>
228
200
  </div>
229
201
 
202
+ <!-- 4. Config -->
230
203
  <div class="form-row">
231
- <label for="node-input-area">
232
- <i class="fa fa-map-marker"></i> Area
233
- </label>
234
- <select id="node-input-area" style="width:55%"></select>
204
+ <label for="node-input-config"><i class="fa fa-cog"></i> Config</label>
205
+ <input type="text" id="node-input-config" />
235
206
  </div>
236
207
 
208
+ <!-- 5. Area -->
237
209
  <div class="form-row">
238
- <label for="node-input-situation">
239
- <i class="fa fa-compass"></i> Situation
240
- </label>
241
- <select id="node-input-situation" style="width:55%">
242
- <option value="in">in</option>
243
- <option value="above">above</option>
244
- <option value="below">below</option>
245
- <option value="outside">outside</option>
246
- <option value="throughout">throughout</option>
247
- <option value="under">under</option>
248
- <option value="over">over</option>
249
- </select>
210
+ <label for="node-input-area"><i class="fa fa-map-marker"></i> Area</label>
211
+ <select id="node-input-area" style="width:55%"></select>
250
212
  </div>
251
213
 
214
+ <!-- 6. Sub-Area -->
252
215
  <div class="form-row">
253
- <label for="node-input-subLocation">
254
- <i class="fa fa-map-marker"></i> Sub-Area
255
- </label>
216
+ <label for="node-input-subLocation"><i class="fa fa-map-marker"></i> Sub-Area</label>
256
217
  <select id="node-input-subLocation" style="width:55%"></select>
257
218
  </div>
258
219
 
220
+ <!-- Discovery Mode -->
259
221
  <div class="form-row">
260
- <label for="node-input-buttonPosition">
261
- <i class="fa fa-hand-pointer-o"></i> Position
262
- </label>
263
- <select id="node-input-buttonPosition" style="width:55%">
264
- <option value="Top Left">Top Left</option>
265
- <option value="Top Right">Top Right</option>
266
- <option value="Bottom Left">Bottom Left</option>
267
- <option value="Bottom Right">Bottom Right</option>
268
- <option value="Top">Top</option>
269
- <option value="Bottom">Bottom</option>
270
- <option value="Left">Left</option>
271
- <option value="Right">Right</option>
272
- <option value="Centre">Centre</option>
273
- <option value="Single">Single</option>
222
+ <label for="node-input-discoveryMode"><i class="fa fa-toggle-on"></i> Discovery Mode</label>
223
+ <select id="node-input-discoveryMode" style="width:55%">
224
+ <option value="enabled">Enabled — discovered and visible in HA</option>
225
+ <option value="hidden">Hidden — discovered but hidden in HA dashboard</option>
226
+ <option value="disabled">Disabled — not discovered, not in HA</option>
274
227
  </select>
275
228
  </div>
276
229
 
277
230
  <hr/>
278
231
 
279
- <!-- ── CONTROLLER ────────────────────────────────────────── -->
280
232
  <div class="form-row">
281
233
  <label style="width:100%; font-weight:bold; color:#999; font-size:0.85em; text-transform:uppercase; letter-spacing:0.05em;">
282
234
  <i class="fa fa-exchange"></i> Controller
@@ -284,27 +236,18 @@
284
236
  </div>
285
237
 
286
238
  <div class="form-row">
287
- <label for="node-input-buttonPayload">
288
- <i class="fa fa-hand-pointer-o"></i> Payload
289
- </label>
290
- <input type="text" id="node-input-buttonPayload"
291
- placeholder="e.g. 10-54" style="width:120px" />
292
- <span style="margin-left:8px; color:#999; font-size:0.85em;">
293
- panelId-GPIOpin
294
- </span>
239
+ <label for="node-input-buttonPayload"><i class="fa fa-hand-pointer-o"></i> Payload</label>
240
+ <input type="text" id="node-input-buttonPayload" placeholder="Required — e.g. 10-54" style="width:120px" />
241
+ <span style="margin-left:8px; color:#999; font-size:0.85em;">panelId-GPIOpin</span>
295
242
  </div>
296
243
 
297
244
  <div class="form-row">
298
- <label for="node-input-subscribeTopic">
299
- <i class="fa fa-exchange"></i> Subscribe topic
300
- </label>
301
- <input type="text" id="node-input-subscribeTopic"
302
- placeholder="Required — e.g. buttons or home/zone/buttons" style="width:55%" />
245
+ <label for="node-input-subscribeTopic"><i class="fa fa-exchange"></i> Subscribe topic</label>
246
+ <input type="text" id="node-input-subscribeTopic" placeholder="Required — e.g. buttons or home/zone/buttons" style="width:55%" />
303
247
  </div>
304
248
 
305
249
  <hr/>
306
250
 
307
- <!-- ── OPTIONS ───────────────────────────────────────────── -->
308
251
  <div class="form-row">
309
252
  <label style="width:100%; font-weight:bold; color:#999; font-size:0.85em; text-transform:uppercase; letter-spacing:0.05em;">
310
253
  <i class="fa fa-sliders"></i> Options
@@ -312,40 +255,27 @@
312
255
  </div>
313
256
 
314
257
  <div class="form-row">
315
- <label for="node-input-haIcon">
316
- <i class="fa fa-image"></i> HA Icon
317
- </label>
318
- <input type="text" id="node-input-haIcon"
319
- placeholder="mdi:gesture-tap-button" style="width:55%" />
258
+ <label for="node-input-haIcon"><i class="fa fa-image"></i> HA Icon</label>
259
+ <input type="text" id="node-input-haIcon" placeholder="mdi:gesture-tap-button" style="width:55%" />
320
260
  </div>
321
261
 
322
262
  <div class="form-row">
323
- <label for="node-input-ledColor">
324
- <i class="fa fa-circle"></i> LED Colour
325
- </label>
263
+ <label for="node-input-ledColor"><i class="fa fa-circle"></i> LED Colour</label>
326
264
  <select id="node-input-ledColor" style="width:120px">
327
- <option value="Blue">Blue</option>
328
- <option value="Red">Red</option>
329
- <option value="Green">Green</option>
330
- <option value="White">White</option>
331
- <option value="Orange">Orange</option>
332
- <option value="None">None</option>
265
+ <option value="Blue">Blue</option><option value="Red">Red</option><option value="Green">Green</option>
266
+ <option value="White">White</option><option value="Orange">Orange</option><option value="None">None</option>
333
267
  </select>
334
268
  </div>
335
269
 
336
270
  <div class="form-row">
337
- <label for="node-input-holdTime">
338
- <i class="fa fa-clock-o"></i> Hold time (s)
339
- </label>
340
- <input type="number" id="node-input-holdTime"
341
- min="0.1" step="0.1" style="width:80px" />
342
- <span style="margin-left:8px; color:#999; font-size:0.85em;">
343
- HA auto-clears binary_sensor after this delay
344
- </span>
271
+ <label for="node-input-holdTime"><i class="fa fa-clock-o"></i> Hold time (s)</label>
272
+ <input type="number" id="node-input-holdTime" min="0.1" step="0.1" style="width:80px" />
273
+ <span style="margin-left:8px; color:#999; font-size:0.85em;">HA auto-clears binary_sensor after this delay</span>
345
274
  </div>
346
275
 
347
276
  </script>
348
277
 
278
+
349
279
  <script type="text/html" data-help-name="ha-mqtt-button">
350
280
  <p>
351
281
  Wall button receiver. Listens for hardware controller MQTT payloads
@@ -33,14 +33,26 @@ module.exports = function (RED) {
33
33
  }, 1500);
34
34
  }
35
35
 
36
+ // Track if already discovered to prevent double-fire
37
+ let _discovered = false;
38
+ function _tryDiscover() {
39
+ if (_discovered) return;
40
+ _discovered = true;
41
+ autoDiscover();
42
+ }
43
+
36
44
  // Auto-discover if broker already connected on deploy
37
45
  if (broker.connected) {
38
- autoDiscover();
46
+ _tryDiscover();
39
47
  }
40
- // Or wait for broker to connect
48
+ // Wait for broker connect event
41
49
  broker.on('connect', function () {
42
- autoDiscover();
50
+ _tryDiscover();
43
51
  });
52
+ // Fallback — if connect event already fired before listener registered
53
+ setTimeout(function () {
54
+ _tryDiscover();
55
+ }, 3000);
44
56
 
45
57
 
46
58
 
@@ -183,17 +195,18 @@ module.exports = function (RED) {
183
195
  }
184
196
 
185
197
 
186
- // ── HTTP endpoints for canvas buttons registered once at module level ──
187
- RED.httpAdmin.post('/ha-mqtt-button/:id/add', RED.auth.needsPermission('ha-mqtt-button.write'), function(req, res) {
198
+ // ── HTTP endpoint for canvas toggle button ───────────────────────────────
199
+ RED.httpAdmin.post('/ha-mqtt-button/:id/toggle', RED.auth.needsPermission('ha-mqtt-button.write'), function(req, res) {
188
200
  const n = RED.nodes.getNode(req.params.id);
189
- if (n) { n.receive({ device: 'add' }); res.sendStatus(200); }
190
- else res.sendStatus(404);
191
- });
192
-
193
- RED.httpAdmin.post('/ha-mqtt-button/:id/remove', RED.auth.needsPermission('ha-mqtt-button.write'), function(req, res) {
194
- const n = RED.nodes.getNode(req.params.id);
195
- if (n) { n.receive({ device: 'remove' }); res.sendStatus(200); }
196
- else res.sendStatus(404);
201
+ if (n) {
202
+ const last = n.context().get('_lastBtn') || 'add';
203
+ const next = last === 'add' ? 'remove' : 'add';
204
+ n.context().set('_lastBtn', next);
205
+ n.receive({ device: next });
206
+ res.json({ action: next });
207
+ } else {
208
+ res.sendStatus(404);
209
+ }
197
210
  });
198
211
 
199
212
  RED.nodes.registerType('ha-mqtt-button', HaMqttButtonNode);