@haydendonald/node-red-contrib-hass-stuff 1.1.7 → 1.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.
package/README.md CHANGED
@@ -511,7 +511,6 @@ A node that controls lights with general scenes that adjust throughout the day w
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) {
@@ -134,7 +134,7 @@ module.exports = function LightControlConfigNode(RED) {
134
134
  friendlyName: `${self.name} - ${sceneValue.friendlyName}`,
135
135
  id: (0, utility_1.getEntityId)("scene", `${self.name}_${sceneKey}`),
136
136
  creationCallback: (response) => { },
137
- activatedCallback: (state, serviceData) => {
137
+ activatedCallback: (state, serviceData, response) => {
138
138
  //Set our scene
139
139
  connectionsConfigNode.sendHASSAction("select.select_option", { entity_id: [(0, utility_1.getEntityId)("select", `${self.name}_current_scene`)] }, {
140
140
  option: sceneValue.friendlyName
@@ -148,7 +148,7 @@ module.exports = function LightControlConfigNode(RED) {
148
148
  friendlyName: `${self.name} - Adaptive`,
149
149
  id: (0, utility_1.getEntityId)("scene", `${self.name}_adaptive`),
150
150
  creationCallback: (response) => { },
151
- activatedCallback: (state, serviceData) => {
151
+ activatedCallback: (state, serviceData, response) => {
152
152
  //Set our scene to adaptive
153
153
  connectionsConfigNode.sendHASSAction("select.select_option", { entity_id: [(0, utility_1.getEntityId)("select", `${self.name}_current_scene`)] }, {
154
154
  option: "Adaptive"
@@ -161,7 +161,7 @@ module.exports = function LightControlConfigNode(RED) {
161
161
  friendlyName: `${self.name} - Turn On`,
162
162
  id: (0, utility_1.getEntityId)("scene", `${self.name}_turn_on`),
163
163
  creationCallback: (response) => { },
164
- activatedCallback: (state, serviceData) => {
164
+ activatedCallback: (state, serviceData, response) => {
165
165
  runLights(serviceData.transition || 1, true);
166
166
  }
167
167
  });
@@ -170,7 +170,7 @@ module.exports = function LightControlConfigNode(RED) {
170
170
  friendlyName: `${self.name} - Turn Off`,
171
171
  id: (0, utility_1.getEntityId)("scene", `${self.name}_turn_off`),
172
172
  creationCallback: (response) => { },
173
- activatedCallback: (state, serviceData) => {
173
+ activatedCallback: (state, serviceData, response) => {
174
174
  connectionsConfigNode.sendHASSAction("light.turn_off", { entity_id: [config.groupEntityId] }, {
175
175
  transition: serviceData.transition || 1
176
176
  });
@@ -181,7 +181,7 @@ module.exports = function LightControlConfigNode(RED) {
181
181
  friendlyName: `${self.name} - Toggle`,
182
182
  id: (0, utility_1.getEntityId)("scene", `${self.name}_toggle`),
183
183
  creationCallback: (response) => { },
184
- activatedCallback: (state, serviceData) => {
184
+ activatedCallback: (state, serviceData, response) => {
185
185
  if (currentState.state == "off") {
186
186
  runLights(serviceData.transition || 1, true);
187
187
  }
@@ -201,11 +201,11 @@ module.exports = function LightControlConfigNode(RED) {
201
201
  "Adaptive"
202
202
  ],
203
203
  defaultState: "Adaptive",
204
- creationCallback: (state) => {
204
+ creationCallback: (state, response) => {
205
205
  currentSceneState = state;
206
206
  runLights(300, false);
207
207
  },
208
- activatedCallback: (state, serviceData) => {
208
+ activatedCallback: (state, serviceData, response) => {
209
209
  currentSceneState = state;
210
210
  }
211
211
  });
@@ -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.0",
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": {