@haydendonald/node-red-contrib-hass-stuff 1.1.7 → 1.2.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.
package/README.md CHANGED
@@ -502,16 +502,15 @@ A node that controls lights with general scenes that adjust throughout the day w
502
502
 
503
503
  ### Features
504
504
  * Adaptive scenes depending on what time of the day it is
505
- * Adaptive scenes depending on luminance sensor *TODO*
505
+ * Adaptive scenes depending on luminance sensor
506
506
  * Night mode entity to force the adaptive scene to be in "night mode"
507
507
  * Ability to turn off entities in night mode
508
508
 
509
509
  ### Dependencies
510
- 1. [Adaptive Lighting](https://github.com/basnijholt/adaptive-lighting)
510
+ 1. [Hue Scene Presets](https://github.com/Hypfer/hass-scene_presets)
511
511
  2. [HASS Sun](https://www.home-assistant.io/integrations/sun/)
512
512
 
513
513
  ## PIR
514
- *TODO*
515
514
 
516
515
  A node that simplifies control of a PIR
517
516
 
@@ -131,8 +131,10 @@ module.exports = function ConnectionsConfigNode(RED) {
131
131
  }
132
132
  currentState = state;
133
133
  //Tell HASS that the button was pressed
134
- self.sendHASSAPI("http", "post", "/api/states/" + entityId, undefined, undefined, data(currentState));
135
- options.changedCallback(currentState, serviceData);
134
+ self.sendHASSAPI("http", "post", "/api/states/" + entityId, (response) => {
135
+ var _a;
136
+ (_a = options.changedCallback) === null || _a === void 0 ? void 0 : _a.call(options, currentState, serviceData, response);
137
+ }, undefined, data(currentState));
136
138
  }
137
139
  };
138
140
  }
@@ -173,8 +175,10 @@ module.exports = function ConnectionsConfigNode(RED) {
173
175
  if (domain == "button" && service == "press" && (serviceData === null || serviceData === void 0 ? void 0 : serviceData.entity_id) == entityId) {
174
176
  const state = new Date();
175
177
  //Tell HASS that the button was pressed
176
- self.sendHASSAPI("http", "post", "/api/states/" + entityId, undefined, undefined, data(state));
177
- options.pressedCallback(state, serviceData);
178
+ self.sendHASSAPI("http", "post", "/api/states/" + entityId, (response) => {
179
+ var _a;
180
+ (_a = options.pressedCallback) === null || _a === void 0 ? void 0 : _a.call(options, state, serviceData, response);
181
+ }, undefined, data(state));
178
182
  }
179
183
  };
180
184
  }
@@ -218,8 +222,10 @@ module.exports = function ConnectionsConfigNode(RED) {
218
222
  }
219
223
  const state = new Date();
220
224
  //Tell HASS that the scene was activated
221
- self.sendHASSAPI("http", "post", "/api/states/" + entityId, undefined, undefined, data(state));
222
- options.activatedCallback(state, serviceData);
225
+ self.sendHASSAPI("http", "post", "/api/states/" + entityId, (response) => {
226
+ var _a;
227
+ (_a = options.activatedCallback) === null || _a === void 0 ? void 0 : _a.call(options, state, serviceData, response);
228
+ }, undefined, data(state));
223
229
  }
224
230
  };
225
231
  }
@@ -263,16 +269,22 @@ module.exports = function ConnectionsConfigNode(RED) {
263
269
  return;
264
270
  }
265
271
  if (service == "select_option") {
266
- self.sendHASSAPI("http", "post", "/api/states/" + entityId, undefined, undefined, data(serviceData.option));
267
- options.activatedCallback(serviceData.option, serviceData);
272
+ self.sendHASSAPI("http", "post", "/api/states/" + entityId, (response) => {
273
+ var _a;
274
+ (_a = options.activatedCallback) === null || _a === void 0 ? void 0 : _a.call(options, serviceData.option, serviceData, response);
275
+ }, undefined, data(serviceData.option));
268
276
  }
269
277
  else if (service == "select_first") {
270
- self.sendHASSAPI("http", "post", "/api/states/" + entityId, undefined, undefined, data(options.options[0] || "unknown"));
271
- options.activatedCallback(options.options[0] || "unknown", serviceData);
278
+ self.sendHASSAPI("http", "post", "/api/states/" + entityId, (response) => {
279
+ var _a;
280
+ (_a = options.activatedCallback) === null || _a === void 0 ? void 0 : _a.call(options, options.options[0] || "unknown", serviceData, response);
281
+ }, undefined, data(options.options[0] || "unknown"));
272
282
  }
273
283
  else if (service == "select_last") {
274
- self.sendHASSAPI("http", "post", "/api/states/" + entityId, undefined, undefined, data(options.options[options.options.length - 1] || "unknown"));
275
- options.activatedCallback(options.options[options.options.length - 1] || "unknown", serviceData);
284
+ self.sendHASSAPI("http", "post", "/api/states/" + entityId, (response) => {
285
+ var _a;
286
+ (_a = options.activatedCallback) === null || _a === void 0 ? void 0 : _a.call(options, options.options[options.options.length - 1] || "unknown", serviceData, response);
287
+ }, undefined, data(options.options[options.options.length - 1] || "unknown"));
276
288
  }
277
289
  else if (service == "select_previous" || service == "select_next") {
278
290
  self.getHASSEntityState(entityId, (currentState) => {
@@ -295,8 +307,10 @@ module.exports = function ConnectionsConfigNode(RED) {
295
307
  index = options.options.length - 1;
296
308
  }
297
309
  }
298
- self.sendHASSAPI("http", "post", "/api/states/" + entityId, undefined, undefined, data(options.options[index] || "unknown"));
299
- options.activatedCallback(options.options[index] || "unknown", serviceData);
310
+ self.sendHASSAPI("http", "post", "/api/states/" + entityId, (response) => {
311
+ var _a;
312
+ (_a = options.activatedCallback) === null || _a === void 0 ? void 0 : _a.call(options, options.options[index] || "unknown", serviceData, response);
313
+ }, undefined, data(options.options[index] || "unknown"));
300
314
  });
301
315
  }
302
316
  }
@@ -334,10 +348,10 @@ module.exports = function ConnectionsConfigNode(RED) {
334
348
  } : undefined);
335
349
  });
336
350
  return (state) => {
337
- self.sendHASSAPI("http", "post", "/api/states/" + entityId, undefined, undefined, data(state));
338
- if (options.changedCallback) {
339
- options.changedCallback(state);
340
- }
351
+ self.sendHASSAPI("http", "post", "/api/states/" + entityId, (response) => {
352
+ var _a;
353
+ (_a = options.changedCallback) === null || _a === void 0 ? void 0 : _a.call(options, state, response);
354
+ }, undefined, data(state));
341
355
  };
342
356
  };
343
357
  self.sendCompanionNotification = function (options) {
@@ -53,7 +53,7 @@
53
53
  <p>
54
54
  The following settings define what the scenes should do. They follow the syntax of [scene] [brightnessPercent]
55
55
  where scene is the scene name, if the same as below values will use the
56
- <a style="font-weight: bold;" href="https://github.com/basnijholt/adaptive-lighting">Adaptive Lighting HACS plugin</a>
56
+ <a style="font-weight: bold;" href="https://github.com/Hypfer/hass-scene_presets">Hue Scene Presets HACS plugin</a>
57
57
  otherwise will send to scene.apply. The brightnessPercent is the brightness percentage to set
58
58
  </p>
59
59
  <ul>
@@ -106,4 +106,19 @@
106
106
  </script>
107
107
 
108
108
  <script type="text/html" data-help-name="light-control-config-node">
109
+ <p>A node that controls lights with general scenes that adjust throughout the day with sleep mode and other features.</p>
110
+
111
+ <h2>Features</h2>
112
+ <ul>
113
+ <li>Adaptive scenes depending on what time of the day it is</li>
114
+ <li>Adaptive scenes depending on luminance sensor</li>
115
+ <li>Night mode entity to force the adaptive scene to be in "night mode"</li>
116
+ <li>Ability to turn off entities in night mode</li>
117
+ </ul>
118
+
119
+ <h2>Dependencies</h2>
120
+ <ul>
121
+ <li><a href="https://github.com/Hypfer/hass-scene_presets" target="_blank">Hue Scene Presets</a></li>
122
+ <li><a href="https://www.home-assistant.io/integrations/sun/" target="_blank">Sun Integration</a></li>
123
+ </ul>
109
124
  </script>
@@ -10,6 +10,7 @@ module.exports = function LightControlConfigNode(RED) {
10
10
  let nightModeState;
11
11
  let currentSceneState;
12
12
  let sunState;
13
+ let lastSentScene;
13
14
  let entitiesOnDuringNight = [];
14
15
  let entitiesOffDuringNight = [];
15
16
  let adaptiveInterval;
@@ -134,7 +135,7 @@ module.exports = function LightControlConfigNode(RED) {
134
135
  friendlyName: `${self.name} - ${sceneValue.friendlyName}`,
135
136
  id: (0, utility_1.getEntityId)("scene", `${self.name}_${sceneKey}`),
136
137
  creationCallback: (response) => { },
137
- activatedCallback: (state, serviceData) => {
138
+ activatedCallback: (state, serviceData, response) => {
138
139
  //Set our scene
139
140
  connectionsConfigNode.sendHASSAction("select.select_option", { entity_id: [(0, utility_1.getEntityId)("select", `${self.name}_current_scene`)] }, {
140
141
  option: sceneValue.friendlyName
@@ -148,7 +149,7 @@ module.exports = function LightControlConfigNode(RED) {
148
149
  friendlyName: `${self.name} - Adaptive`,
149
150
  id: (0, utility_1.getEntityId)("scene", `${self.name}_adaptive`),
150
151
  creationCallback: (response) => { },
151
- activatedCallback: (state, serviceData) => {
152
+ activatedCallback: (state, serviceData, response) => {
152
153
  //Set our scene to adaptive
153
154
  connectionsConfigNode.sendHASSAction("select.select_option", { entity_id: [(0, utility_1.getEntityId)("select", `${self.name}_current_scene`)] }, {
154
155
  option: "Adaptive"
@@ -161,7 +162,7 @@ module.exports = function LightControlConfigNode(RED) {
161
162
  friendlyName: `${self.name} - Turn On`,
162
163
  id: (0, utility_1.getEntityId)("scene", `${self.name}_turn_on`),
163
164
  creationCallback: (response) => { },
164
- activatedCallback: (state, serviceData) => {
165
+ activatedCallback: (state, serviceData, response) => {
165
166
  runLights(serviceData.transition || 1, true);
166
167
  }
167
168
  });
@@ -170,7 +171,7 @@ module.exports = function LightControlConfigNode(RED) {
170
171
  friendlyName: `${self.name} - Turn Off`,
171
172
  id: (0, utility_1.getEntityId)("scene", `${self.name}_turn_off`),
172
173
  creationCallback: (response) => { },
173
- activatedCallback: (state, serviceData) => {
174
+ activatedCallback: (state, serviceData, response) => {
174
175
  connectionsConfigNode.sendHASSAction("light.turn_off", { entity_id: [config.groupEntityId] }, {
175
176
  transition: serviceData.transition || 1
176
177
  });
@@ -181,7 +182,7 @@ module.exports = function LightControlConfigNode(RED) {
181
182
  friendlyName: `${self.name} - Toggle`,
182
183
  id: (0, utility_1.getEntityId)("scene", `${self.name}_toggle`),
183
184
  creationCallback: (response) => { },
184
- activatedCallback: (state, serviceData) => {
185
+ activatedCallback: (state, serviceData, response) => {
185
186
  if (currentState.state == "off") {
186
187
  runLights(serviceData.transition || 1, true);
187
188
  }
@@ -201,11 +202,11 @@ module.exports = function LightControlConfigNode(RED) {
201
202
  "Adaptive"
202
203
  ],
203
204
  defaultState: "Adaptive",
204
- creationCallback: (state) => {
205
+ creationCallback: (state, response) => {
205
206
  currentSceneState = state;
206
207
  runLights(300, false);
207
208
  },
208
- activatedCallback: (state, serviceData) => {
209
+ activatedCallback: (state, serviceData, response) => {
209
210
  currentSceneState = state;
210
211
  }
211
212
  });
@@ -229,11 +230,16 @@ module.exports = function LightControlConfigNode(RED) {
229
230
  };
230
231
  //When we get a message from a node on the NodeRED flows
231
232
  this.msgReceived = function (msg, senderIds) { };
232
- const activateScene = (scene, transitionSec, turnLightsOn, entitiesOn, entitiesOff) => {
233
+ const activateScene = (scene, transitionSec, turnLightsOn, entitiesOn, entitiesOff, forceSend) => {
233
234
  //If the lights are off and we are not to turn the lights on don't do anything
234
235
  if (turnLightsOn == false && currentState.state == "off") {
235
236
  return;
236
237
  }
238
+ //Don't send the same scene again
239
+ if (forceSend != true && scene.sceneName == lastSentScene) {
240
+ return;
241
+ }
242
+ lastSentScene = scene.sceneName;
237
243
  //Is not a scene preset scene if we have a entity id
238
244
  if (scene.sceneName.includes(".")) {
239
245
  //Run via hass scene.turn_on
@@ -242,6 +248,14 @@ module.exports = function LightControlConfigNode(RED) {
242
248
  }, {
243
249
  transition: transitionSec
244
250
  });
251
+ //Send to the node output
252
+ self.sendMsg({
253
+ topic: "sceneSent",
254
+ payload: {
255
+ scene,
256
+ transitionSec
257
+ }
258
+ });
245
259
  }
246
260
  //Is a scene preset
247
261
  else {
@@ -250,8 +264,7 @@ module.exports = function LightControlConfigNode(RED) {
250
264
  self.error(`Scene preset not found for ${scene.sceneName}. Please use scene.<presetname> if this is not a scene i know about`);
251
265
  return;
252
266
  }
253
- //Run via adaptive lights
254
- connectionsConfigNode.sendHASSAction("scene_presets.apply_preset", undefined, {
267
+ const msg = {
255
268
  brightness: (scene.brightnessPct / 100.0) * 255,
256
269
  transition: transitionSec,
257
270
  preset_id: sceneId,
@@ -260,7 +273,9 @@ module.exports = function LightControlConfigNode(RED) {
260
273
  targets: {
261
274
  entity_id: entitiesOn ? entitiesOn : [config.groupEntityId]
262
275
  }
263
- }, undefined);
276
+ };
277
+ //Run via adaptive lights
278
+ connectionsConfigNode.sendHASSAction("scene_presets.apply_preset", undefined, msg, undefined);
264
279
  //Run any lights off that need to be off
265
280
  if (entitiesOff && entitiesOff.length > 0) {
266
281
  connectionsConfigNode.sendHASSAction("light.turn_off", {
@@ -269,6 +284,14 @@ module.exports = function LightControlConfigNode(RED) {
269
284
  transition: transitionSec
270
285
  });
271
286
  }
287
+ //Send to the node output
288
+ self.sendMsg({
289
+ topic: "sceneSent",
290
+ payload: {
291
+ scene,
292
+ transitionSec
293
+ }
294
+ });
272
295
  }
273
296
  };
274
297
  const runLights = (transitionSec, turnLightsOn) => {
@@ -284,7 +307,7 @@ module.exports = function LightControlConfigNode(RED) {
284
307
  activateScene(scene, transitionSec, turnLightsOn);
285
308
  }
286
309
  };
287
- const runAdaptive = (transitionSec, turnLightsOn) => {
310
+ const runAdaptive = (transitionSec, turnLightsOn, forceSend) => {
288
311
  let entitiesOn;
289
312
  let entitiesOff;
290
313
  //Decide what scene to send
@@ -327,12 +350,12 @@ module.exports = function LightControlConfigNode(RED) {
327
350
  }
328
351
  }
329
352
  //Send it
330
- activateScene(scene, transitionSec, turnLightsOn, entitiesOn, entitiesOff);
353
+ activateScene(scene, transitionSec, turnLightsOn, entitiesOn, entitiesOff, forceSend);
331
354
  //Start our interval to update the adaptive scene every minute
332
355
  clearTimeout(adaptiveInterval);
333
356
  adaptiveInterval = setTimeout(() => {
334
- runAdaptive(300, false);
335
- }, 60000);
357
+ runAdaptive(300, false, true);
358
+ }, 300000);
336
359
  };
337
360
  };
338
361
  RED.nodes.registerType("light-control-config-node", register);
@@ -2,7 +2,7 @@
2
2
  RED.nodes.registerType("light-control-node", {
3
3
  category: "HASS Stuff",
4
4
  color: "#ffcc00",
5
- inputs: 1,
5
+ inputs: 0,
6
6
  outputs: 1,
7
7
  icon: "bulb.svg",
8
8
  paletteLabel: "Light Control",
@@ -28,4 +28,36 @@
28
28
  </div>
29
29
  </script>
30
30
  <script type="text/html" data-help-name="light-control-node">
31
+ <p>A node that controls lights with general scenes that adjust throughout the day with sleep mode and other features.</p>
32
+
33
+ <h2>Features</h2>
34
+ <ul>
35
+ <li>Adaptive scenes depending on what time of the day it is</li>
36
+ <li>Adaptive scenes depending on luminance sensor</li>
37
+ <li>Night mode entity to force the adaptive scene to be in "night mode"</li>
38
+ <li>Ability to turn off entities in night mode</li>
39
+ </ul>
40
+
41
+ <h2>Dependencies</h2>
42
+ <ul>
43
+ <li><a href="https://github.com/Hypfer/hass-scene_presets" target="_blank">Hue Scene Presets</a></li>
44
+ <li><a href="https://www.home-assistant.io/integrations/sun/" target="_blank">Sun Integration</a></li>
45
+ </ul>
46
+
47
+ <h2>Output</h2>
48
+ <p>This node can output the following messages</p>
49
+ <ul>
50
+ <li>Scene Sent - A scene has been sent to the lights</li>
51
+ <pre><code>
52
+ {
53
+ topic: "sceneSent",
54
+ payload: {
55
+ friendlyName: "Concentrate",
56
+ sceneName: "sunFlare",
57
+ brightnessPct: 100
58
+ }
59
+ }
60
+ </code></pre>
61
+ </ul>
62
+
31
63
  </script>
@@ -9,10 +9,6 @@ module.exports = function LightControlNode(RED) {
9
9
  lightControlConfigNode.addMsgCallback(this.id, (msg) => {
10
10
  this.send(msg);
11
11
  });
12
- //When an input message is received
13
- this.on("input", (msg, send, done) => {
14
- lightControlConfigNode.msgReceived(msg, [this.id]);
15
- });
16
12
  }
17
13
  RED.nodes.registerType("light-control-node", register);
18
14
  };
@@ -0,0 +1,68 @@
1
+ <script type="text/javascript" id="node-PIR-control-config-node">
2
+ RED.nodes.registerType("PIR-control-config-node", {
3
+ category: "config",
4
+ defaults: {
5
+ name: { value: "", required: true },
6
+ connectionsConfigNode: { value: "", type: "connections-config-node", required: true },
7
+ PIROccupancyEntity: { value: "", required: true },
8
+ luminanceEntity: { value: "", required: false },
9
+ minBrightnessLevel: { value: "", required: false },
10
+ maxBrightnessLevel: { value: "", required: false },
11
+ turnOffAfterMs: { value: "0", default: "0", required: true },
12
+ turnOnAfterMs: { value: "0", default: "0", required: true },
13
+ enabledByDefault: { value: true, default: true, required: true }
14
+ },
15
+ label: function () {
16
+ return this.name || "PIR Control Config"
17
+ }
18
+ });
19
+ </script>
20
+
21
+ <script type="text/html" data-template-name="PIR-control-config-node">
22
+ <div class="form-row">
23
+ <label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
24
+ <input type="text" id="node-config-input-name" placeholder="Name">
25
+ </div>
26
+ <div class="form-row">
27
+ <label for="node-config-input-connectionsConfigNode">Config</label>
28
+ <input type="text" id="node-config-input-connectionsConfigNode" />
29
+ </div>
30
+ <div class="form-row">
31
+ <p>The entity id of the PIR occupancy sensor</p>
32
+ <label for="node-config-input-PIROccupancyEntity">PIR Occupancy Entity</label>
33
+ <input type="text" id="node-config-input-PIROccupancyEntity" />
34
+ </div>
35
+ <div class="form-row">
36
+ <p>The entity id of the luminance sensor. If not set will disable this feature</p>
37
+ <label for="node-config-input-luminanceEntity">Luminance Entity</label>
38
+ <input type="text" id="node-config-input-luminanceEntity" />
39
+ </div>
40
+ <div class="form-row">
41
+ <p>The minimum brightness level of the luminance sensor to trigger the PIR. If not set will disable this feature</p>
42
+ <label for="node-config-input-minBrightnessLevel">Min Brightness Level</label>
43
+ <input type="number" id="node-config-input-minBrightnessLevel" />
44
+ </div>
45
+ <div class="form-row">
46
+ <p>The maximum brightness level of the luminance sensor to trigger the PIR. If not set will disable this feature</p>
47
+ <label for="node-config-input-maxBrightnessLevel">Max Brightness Level</label>
48
+ <input type="number" id="node-config-input-maxBrightnessLevel" />
49
+ </div>
50
+ <div class="form-row">
51
+ <p>The minimum time in milliseconds of no detection before triggering the "not detected" output</p>
52
+ <label for="node-config-input-turnOffAfterMs">Turn Off After (ms)</label>
53
+ <input type="number" id="node-config-input-turnOffAfterMs" />
54
+ </div>
55
+ <div class="form-row">
56
+ <p>The minimum time in milliseconds of detection before triggering the "detected" output</p>
57
+ <label for="node-config-input-turnOnAfterMs">Turn On After (ms)</label>
58
+ <input type="number" id="node-config-input-turnOnAfterMs" />
59
+ </div>
60
+ <div class="form-row">
61
+ <p>The default state of the enabled boolean entity when it's added to Home Assistant</p>
62
+ <label for="node-config-input-enabledByDefault">Enabled By Default</label>
63
+ <input type="checkbox" id="node-config-input-enabledByDefault" />
64
+ </div>
65
+ </script>
66
+
67
+ <script type="text/html" data-help-name="PIR-control-config-node">
68
+ </script>
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ const baseConfigNode_1 = require("../baseConfigNode");
3
+ const utility_1 = require("../utility");
4
+ module.exports = function PIRControlConfigNode(RED) {
5
+ const register = function (config) {
6
+ const self = this;
7
+ let PIROccupancyState;
8
+ let luminanceState;
9
+ let enabledState;
10
+ let detectedTimeout;
11
+ let notDetectedTimeout;
12
+ RED.nodes.createNode(this, config);
13
+ (0, baseConfigNode_1.assignBaseConfigNode)(this);
14
+ const connectionsConfigNode = RED.nodes.getNode(config.connectionsConfigNode);
15
+ let errored = false;
16
+ if (!config.connectionsConfigNode || !connectionsConfigNode) {
17
+ this.error("Connections Config Node is required");
18
+ errored = true;
19
+ }
20
+ if (!config.PIROccupancyEntity) {
21
+ this.error("PIR occupancy entity is required");
22
+ errored = true;
23
+ }
24
+ if (!config.enabledByDefault) {
25
+ this.error("Enabled by default is required");
26
+ errored = true;
27
+ }
28
+ if (errored) {
29
+ return;
30
+ }
31
+ //When HASS is ready
32
+ connectionsConfigNode.hassEventReadyCallbacks[this.id] = function (msg) {
33
+ //Get the current state of the occupancy sensor
34
+ connectionsConfigNode.getHASSEntityState(config.PIROccupancyEntity, (payload, data) => {
35
+ PIROccupancyState = data.data;
36
+ });
37
+ //If there is a luminance entity get it's state
38
+ if (config.luminanceEntity && config.luminanceEntity != "") {
39
+ connectionsConfigNode.getHASSEntityState(config.luminanceEntity, (payload, data) => {
40
+ luminanceState = data.data;
41
+ });
42
+ }
43
+ //Add the enabled input boolean
44
+ connectionsConfigNode.addHASSInputBoolean({
45
+ friendlyName: `${self.name} - Enabled`,
46
+ id: (0, utility_1.getEntityId)("input_boolean", `${self.name}_enabled`),
47
+ defaultState: config.enabledByDefault ? "on" : "off",
48
+ creationCallback: (state, response) => {
49
+ enabledState = state;
50
+ },
51
+ changedCallback: (state, serviceData) => {
52
+ enabledState = state;
53
+ }
54
+ });
55
+ };
56
+ //When a state change happens in home assistant
57
+ connectionsConfigNode.hassEventStateChangeCallbacks[this.id] = function (entityId, oldState, newState) {
58
+ switch (entityId) {
59
+ case config.PIROccupancyEntity: {
60
+ PIROccupancyState = newState;
61
+ handle();
62
+ break;
63
+ }
64
+ case config.luminanceEntity: {
65
+ luminanceState = newState;
66
+ break;
67
+ }
68
+ }
69
+ };
70
+ function handle() {
71
+ //Don't do anything if the PIR is disabled
72
+ if (enabledState == "off") {
73
+ return;
74
+ }
75
+ //Don't do anything if the luminance is not enough
76
+ if (config.minBrightnessLevel && parseInt(luminanceState.state) < parseInt(config.minBrightnessLevel)) {
77
+ return;
78
+ }
79
+ //Don't do anything if the luminance is too much
80
+ if (config.maxBrightnessLevel && parseInt(luminanceState.state) > parseInt(config.maxBrightnessLevel)) {
81
+ return;
82
+ }
83
+ const msg = {
84
+ payload: {
85
+ PIROccupancyState,
86
+ enabledState,
87
+ luminanceState
88
+ }
89
+ };
90
+ //Send the detected event
91
+ if (PIROccupancyState.state == "on") {
92
+ clearTimeout(notDetectedTimeout);
93
+ if (config.turnOnAfterMs) {
94
+ detectedTimeout = setTimeout(() => {
95
+ sendDetectedMsg(msg);
96
+ }, parseInt(config.turnOnAfterMs));
97
+ }
98
+ else {
99
+ sendDetectedMsg(msg);
100
+ }
101
+ }
102
+ //Send the not detected event
103
+ if (PIROccupancyState.state == "off") {
104
+ clearTimeout(detectedTimeout);
105
+ if (config.turnOffAfterMs) {
106
+ notDetectedTimeout = setTimeout(() => {
107
+ sendNotDetectedMsg(msg);
108
+ }, parseInt(config.turnOffAfterMs));
109
+ }
110
+ else {
111
+ sendNotDetectedMsg(msg);
112
+ }
113
+ }
114
+ }
115
+ function sendDetectedMsg(msg) {
116
+ self.sendMsg([msg]);
117
+ }
118
+ function sendNotDetectedMsg(msg) {
119
+ self.sendMsg([undefined, msg]);
120
+ }
121
+ };
122
+ RED.nodes.registerType("PIR-control-config-node", register);
123
+ };
@@ -0,0 +1,32 @@
1
+ <script type="text/javascript" id="node-PIR-control-node">
2
+ RED.nodes.registerType("PIR-control-node", {
3
+ category: "HASS Stuff",
4
+ color: "#ffcc00",
5
+ inputs: 0,
6
+ outputs: 2,
7
+ outputLabels: ["detected", "not detected"],
8
+ icon: "alert.svg",
9
+ paletteLabel: "PIR Control",
10
+ defaults: {
11
+ name: { value: "" },
12
+ PIRControlConfigNode: { value: '', type: "PIR-control-config-node", required: true }
13
+ },
14
+ label: function () {
15
+ return this.name || "PIR Control"
16
+ }
17
+ });
18
+ </script>
19
+
20
+
21
+ <script type="text/html" data-template-name="PIR-control-node">
22
+ <div class="form-row">
23
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
24
+ <input type="text" id="node-input-name" placeholder="Name">
25
+ </div>
26
+ <div class="form-row">
27
+ <label for="node-input-PIRControlConfigNode">Config</label>
28
+ <input type="text" id="node-input-PIRControlConfigNode" />
29
+ </div>
30
+ </script>
31
+ <script type="text/html" data-help-name="PIR-control-node">
32
+ </script>
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ const baseNode_1 = require("../baseNode");
3
+ module.exports = function PIRControlNode(RED) {
4
+ function register(config) {
5
+ RED.nodes.createNode(this, config);
6
+ (0, baseNode_1.assignBaseNode)(this);
7
+ const PIRControlConfigNode = RED.nodes.getNode(config.PIRControlConfigNode);
8
+ //When a config node wants to send a message to the output
9
+ PIRControlConfigNode.addMsgCallback(this.id, (msg) => {
10
+ this.send(msg);
11
+ });
12
+ //When an input message is received
13
+ this.on("input", (msg, send, done) => {
14
+ PIRControlConfigNode.msgReceived(msg, [this.id]);
15
+ });
16
+ }
17
+ RED.nodes.registerType("PIR-control-node", register);
18
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haydendonald/node-red-contrib-hass-stuff",
3
- "version": "1.1.7",
3
+ "version": "1.2.1",
4
4
  "description": "A collection of stuff I use on my Node Red + Home Assistant server. This could be of use for others, i don't know..",
5
5
  "devDependencies": {
6
6
  "@types/node": "^18.14.0",
@@ -28,7 +28,9 @@
28
28
  "ConnectionsNode": "dist/Connections/connectionsNode.js",
29
29
  "LightControlConfigNode": "dist/LightControl/lightControlConfigNode.js",
30
30
  "LightControlNode": "dist/LightControl/lightControlNode.js",
31
- "EVChargingPriceNode": "dist/EVChargingPrice/EVChargingPriceNode.js"
31
+ "EVChargingPriceNode": "dist/EVChargingPrice/EVChargingPriceNode.js",
32
+ "PIRControlConfigNode": "dist/PIRControl/PIRControlConfigNode.js",
33
+ "PIRControlNode": "dist/PIRControl/PIRControlNode.js"
32
34
  }
33
35
  },
34
36
  "publishConfig": {