node-red-contrib-homebridge-automation 0.1.12-beta.12 → 0.1.12-beta.13

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-homebridge-automation",
3
- "version": "0.1.12-beta.12",
3
+ "version": "0.1.12-beta.13",
4
4
  "description": "NodeRED Automation for HomeBridge",
5
5
  "main": "src/HAP-NodeRed.js",
6
6
  "scripts": {
@@ -4,6 +4,7 @@ var Queue = require('better-queue');
4
4
 
5
5
  const HBConfNode = require('./hbConfigNode');
6
6
  const HbEventNode = require('./hbEventNode'); // Import the class
7
+ const HbResumeNode = require('./hbResumeNode'); // Import the class
7
8
 
8
9
  module.exports = function (RED) {
9
10
  var evDevices = [];
@@ -87,180 +88,12 @@ module.exports = function (RED) {
87
88
 
88
89
  function hbResumeNode(n) {
89
90
  RED.nodes.createNode(this, n);
90
- this.conf = RED.nodes.getNode(n.conf);
91
- this.confId = n.conf;
92
- this.device = n.device;
93
- this.service = n.Service;
94
- this.name = n.name;
95
- this.fullName = n.name + ' - ' + n.Service;
96
- var node = this;
97
-
98
- node.state = null;
99
- node.lastMessageTime = null;
100
- node.lastMessageValue = null;
101
- node.lastPayload = {
102
- On: false
103
- };
104
-
105
- node.on('input', function (msg) {
106
- this.msg = msg;
107
- debug("hbResume.input: %s input", node.fullName, JSON.stringify(msg));
108
- if (typeof msg.payload === "object") {
109
- // Using this to validate input message contains valid Accessory Characteristics
110
- if (node.hbDevice) { // not populated until initialization is complete
111
- var message = _createControlMessage.call(this, msg.payload, node, node.hbDevice);
112
-
113
- if (message.characteristics.length > 0) {
114
- var newMsg;
115
- if (!msg.payload.On) {
116
- // false / Turn Off
117
- // debug("hbResume-Node lastPayload %s", JSON.stringify(node.lastPayload));
118
- if (node.lastPayload.On) {
119
- // last msg was on, restore previous state
120
- newMsg = {
121
- name: node.name,
122
- _device: node.device,
123
- _confId: node.confId
124
- };
125
- if (node.hbDevice) {
126
- newMsg.Homebridge = node.hbDevice.homebridge;
127
- newMsg.Manufacturer = node.hbDevice.manufacturer;
128
- newMsg.Type = node.hbDevice.deviceType;
129
- }
130
- newMsg.payload = node.state;
131
- } else {
132
- // last msg was off, pass thru
133
- node.state = JSON.parse(JSON.stringify(msg.payload));
134
- newMsg = msg;
135
- }
136
- } else {
137
- // True / Turn on
138
- newMsg = msg;
139
- }
140
- // Off messages should not include brightness
141
- node.send((newMsg.payload.On ? newMsg : newMsg.payload = {
142
- On: false
143
- }, newMsg));
144
- debug("hbResume.input: %s output", node.fullName, JSON.stringify(newMsg));
145
- node.status({
146
- text: JSON.stringify(newMsg.payload).slice(0, 30) + '...',
147
- shape: 'dot',
148
- fill: 'green'
149
- });
150
- clearTimeout(node.timeout);
151
- node.timeout = setTimeout(function () {
152
- node.status({});
153
- }, 10 * 1000);
154
- node.lastMessageValue = newMsg.payload;
155
- node.lastMessageTime = Date.now();
156
- // debug("hbResume.input: %s updating lastPayload %s", node.fullName, JSON.stringify(msg.payload));
157
- node.lastPayload = JSON.parse(JSON.stringify(msg.payload)); // store value not reference
158
- }
159
- } else {
160
- node.error("Homebridge not initialized - 1", this.msg);
161
- node.status({
162
- text: 'Homebridge not initialized -1',
163
- shape: 'ring',
164
- fill: 'red'
165
- });
166
- }
167
- } else {
168
- node.error("Payload should be an JSON object containing device characteristics and values, ie {\"On\":false, \"Brightness\":0 }\nValid values include: " + node.hbDevice.descriptions, this.msg);
169
- node.status({
170
- text: 'Invalid payload',
171
- shape: 'ring',
172
- fill: 'red'
173
- });
174
- }
175
- });
176
-
177
- node.command = function (event) {
178
- // debug("hbResume received event: %s ->", node.fullName, event);
179
- // debug("hbResume - internals %s millis, old %s, event %s, previous %s", Date.now() - node.lastMessageTime, node.lastMessageValue, event.status, node.state);
180
- // Don't update for events originating from here
181
- // if Elapsed is greater than 5 seconds, update stored state
182
- // if Elapsed is less then 5, and lastMessage doesn't match event update stored state
183
-
184
- var payload = Object.assign({}, node.state);
185
-
186
- // debug("should be true", _getObjectDiff(payload, node.state).length);
187
-
188
- payload = Object.assign(payload, _convertHBcharactericToNode([event], node));
189
-
190
- // debug("should be false", _getObjectDiff(payload, node.state).length);
191
-
192
- debug("hbResume.event: %s %s -> %s", node.fullName, JSON.stringify(node.state), JSON.stringify(payload));
193
-
194
- if (event.status === true && event.value !== undefined) {
195
- if ((Date.now() - node.lastMessageTime) > 5000) {
196
- debug("hbResume.update: %s - updating stored event >5", node.fullName, payload);
197
- node.state = JSON.parse(JSON.stringify(payload));
198
- } else if (_getObjectDiff(payload, node.lastMessageValue).length > 0) {
199
- // debug("hbResume - updating stored event !=", payload, node.lastMessageValue);
200
- // node.state = payload;
201
- }
202
- } else if (event.status === true) {
203
- node.status({
204
- text: 'connected',
205
- shape: 'dot',
206
- fill: 'green'
207
- });
208
- } else {
209
- node.status({
210
- text: 'disconnected: ' + event.status,
211
- shape: 'ring',
212
- fill: 'red'
213
- });
214
- }
215
- };
216
-
217
- node.conf.register(node, function () {
218
- debug("hbResume.register:", node.fullName);
219
- this.hbDevice = hbDevices.findDevice(node.device, {
220
- perms: 'pw'
221
- });
222
- if (this.hbDevice) {
223
- _status(node.device, node, {
224
- perms: 'pw'
225
- }, function (err, message) {
226
- if (!err) {
227
- node.state = _convertHBcharactericToNode(message.characteristics, node);
228
- debug("hbResume received: %s = %s", node.fullName, JSON.stringify(message.characteristics).slice(0, 80) + '...');
229
- } else {
230
- node.error(err);
231
- }
232
- });
233
- node.hbDevice = this.hbDevice;
234
- node.deviceType = this.hbDevice.deviceType;
235
- // Register for events
236
- node.listener = node.command;
237
- node.eventName = [];
238
- // node.eventName = this.hbDevice.host + this.hbDevice.port + this.hbDevice.aid;
239
- // homebridge.on(this.hbDevice.host + this.hbDevice.port + this.hbDevice.aid, node.command);
240
- this.hbDevice.eventRegisters.forEach(function (event) {
241
- homebridge.on(node.hbDevice.id + event.aid + event.iid, node.command);
242
- node.eventName.push(node.hbDevice.id + event.aid + event.iid);
243
- });
244
- node.status({
245
- text: 'connected',
246
- shape: 'dot',
247
- fill: 'green'
248
- });
249
- clearTimeout(node.timeout);
250
- node.timeout = setTimeout(function () {
251
- node.status({});
252
- }, 30 * 1000);
253
- } else {
254
- node.error("365:Can't find device " + node.device, null);
255
- }
256
- }.bind(this));
257
-
258
- node.on('close', function (callback) {
259
- node.conf.deregister(node, callback);
260
- });
91
+
92
+ // Create instance of HbEventNode class to handle events
93
+ new HbResumeNode(this, n); // Pass current node and config object
261
94
  }
262
95
 
263
- RED.nodes.registerType("hb-resume", hbResume);
96
+ RED.nodes.registerType("hb-resume", hbResumeNode);
264
97
 
265
98
  /**
266
99
  * hbControl - description
@@ -0,0 +1,58 @@
1
+ var debug = require('debug')('hapNodeRed:hbControlNode');
2
+
3
+ function hbControl(n) {
4
+ RED.nodes.createNode(this, n);
5
+ this.conf = RED.nodes.getNode(n.conf); // The configuration node
6
+ this.confId = n.conf;
7
+ this.device = n.device;
8
+ this.service = n.Service;
9
+ this.name = n.name;
10
+ this.fullName = n.name + ' - ' + n.Service;
11
+
12
+ var node = this;
13
+
14
+ node.on('input', function (msg) {
15
+ this.msg = msg;
16
+ _control.call(this, node, msg.payload, function (err, data) {
17
+ // debug('hbControl complete [%s] - [%s]', node, node.hbDevice); // Images produce alot of noise
18
+ if (!err && data && (node.deviceType == '00000110' || node.deviceType == '00000111')) {
19
+ const msg = {
20
+ name: node.name,
21
+ payload: node.state,
22
+ _device: node.device,
23
+ _confId: node.confId
24
+ };
25
+ if (node.hbDevice) {
26
+ msg.Homebridge = node.hbDevice.homebridge;
27
+ msg.Manufacturer = node.hbDevice.manufacturer;
28
+ msg.Service = node.hbDevice.deviceType;
29
+ }
30
+ msg.payload = data;
31
+ node.send(msg);
32
+ } else if (err) {
33
+ node.error(err, this.msg);
34
+ }
35
+ }.bind(this));
36
+
37
+ });
38
+
39
+ node.on('close', function (callback) {
40
+ callback();
41
+ });
42
+
43
+ node.conf.register(node, function () {
44
+ debug("hbControl.register:", node.fullName);
45
+ this.hbDevice = hbDevices.findDevice(node.device);
46
+ // console.log('hbControl Register', this.hbDevice)
47
+ if (this.hbDevice) {
48
+ node.hbDevice = this.hbDevice;
49
+ node.deviceType = this.hbDevice.type;
50
+ // Register for events
51
+ node.listener = node.command;
52
+ // node.eventName = this.hbDevice.host + this.hbDevice.port + this.hbDevice.aid;
53
+ } else {
54
+ node.error("437:Can't find device " + node.device, null);
55
+ // this.error("Missing device " + node.device);
56
+ }
57
+ });
58
+ }
@@ -1,176 +1,137 @@
1
1
  const debug = require('debug')('hapNodeRed:hbResumeNode');
2
2
 
3
- function hbResumeNode(n) {
4
- RED.nodes.createNode(this, n);
5
- this.conf = RED.nodes.getNode(n.conf);
6
- this.confId = n.conf;
7
- this.device = n.device;
8
- this.service = n.Service;
9
- this.name = n.name;
10
- this.fullName = n.name + ' - ' + n.Service;
11
- var node = this;
12
-
13
- node.state = null;
14
- node.lastMessageTime = null;
15
- node.lastMessageValue = null;
16
- node.lastPayload = {
17
- On: false
18
- };
19
-
20
- node.on('input', function (msg) {
3
+ class HbResumeNode {
4
+ constructor(nodeConfig, RED) {
5
+ RED.nodes.createNode(this, nodeConfig);
6
+ this.conf = RED.nodes.getNode(nodeConfig.conf);
7
+ this.confId = nodeConfig.conf;
8
+ this.device = nodeConfig.device;
9
+ this.service = nodeConfig.Service;
10
+ this.name = nodeConfig.name;
11
+ this.fullName = `${nodeConfig.name} - ${nodeConfig.Service}`;
12
+ this.state = null;
13
+ this.lastMessageTime = null;
14
+ this.lastMessageValue = null;
15
+ this.lastPayload = { On: false };
16
+ this.timeout = null;
17
+
18
+ this.on('input', this.handleInput.bind(this));
19
+
20
+ this.command = this.handleCommand.bind(this);
21
+
22
+ this.conf.register(this, this.handleDeviceRegistration.bind(this));
23
+
24
+ this.on('close', (callback) => {
25
+ this.conf.deregister(this, callback);
26
+ });
27
+ }
28
+
29
+ handleInput(msg) {
21
30
  this.msg = msg;
22
- debug("hbResume.input: %s input", node.fullName, JSON.stringify(msg));
31
+ debug("hbResume.input: %s input", this.fullName, JSON.stringify(msg));
32
+
23
33
  if (typeof msg.payload === "object") {
24
- // Using this to validate input message contains valid Accessory Characteristics
25
- if (node.hbDevice) { // not populated until initialization is complete
26
- var message = _createControlMessage.call(this, msg.payload, node, node.hbDevice);
34
+ if (this.hbDevice) {
35
+ const message = _createControlMessage.call(this, msg.payload, this, this.hbDevice);
27
36
 
28
37
  if (message.characteristics.length > 0) {
29
- var newMsg;
38
+ let newMsg;
30
39
  if (!msg.payload.On) {
31
- // false / Turn Off
32
- // debug("hbResume-Node lastPayload %s", JSON.stringify(node.lastPayload));
33
- if (node.lastPayload.On) {
34
- // last msg was on, restore previous state
40
+ if (this.lastPayload.On) {
35
41
  newMsg = {
36
- name: node.name,
37
- _device: node.device,
38
- _confId: node.confId
42
+ name: this.name,
43
+ _device: this.device,
44
+ _confId: this.confId,
45
+ payload: this.state,
46
+ Homebridge: this.hbDevice?.homebridge,
47
+ Manufacturer: this.hbDevice?.manufacturer,
48
+ Type: this.hbDevice?.deviceType,
39
49
  };
40
- if (node.hbDevice) {
41
- newMsg.Homebridge = node.hbDevice.homebridge;
42
- newMsg.Manufacturer = node.hbDevice.manufacturer;
43
- newMsg.Type = node.hbDevice.deviceType;
44
- }
45
- newMsg.payload = node.state;
46
50
  } else {
47
- // last msg was off, pass thru
48
- node.state = JSON.parse(JSON.stringify(msg.payload));
51
+ this.state = JSON.parse(JSON.stringify(msg.payload));
49
52
  newMsg = msg;
50
53
  }
51
54
  } else {
52
- // True / Turn on
53
55
  newMsg = msg;
54
56
  }
55
- // Off messages should not include brightness
56
- node.send((newMsg.payload.On ? newMsg : newMsg.payload = {
57
- On: false
58
- }, newMsg));
59
- debug("hbResume.input: %s output", node.fullName, JSON.stringify(newMsg));
60
- node.status({
61
- text: JSON.stringify(newMsg.payload).slice(0, 30) + '...',
62
- shape: 'dot',
63
- fill: 'green'
64
- });
65
- clearTimeout(node.timeout);
66
- node.timeout = setTimeout(function () {
67
- node.status({});
68
- }, 10 * 1000);
69
- node.lastMessageValue = newMsg.payload;
70
- node.lastMessageTime = Date.now();
71
- // debug("hbResume.input: %s updating lastPayload %s", node.fullName, JSON.stringify(msg.payload));
72
- node.lastPayload = JSON.parse(JSON.stringify(msg.payload)); // store value not reference
57
+
58
+ this.send(newMsg.payload.On ? newMsg : { ...newMsg, payload: { On: false } });
59
+ debug("hbResume.input: %s output", this.fullName, JSON.stringify(newMsg));
60
+ this.updateStatus(newMsg.payload);
61
+ this.lastMessageValue = newMsg.payload;
62
+ this.lastMessageTime = Date.now();
63
+ this.lastPayload = JSON.parse(JSON.stringify(msg.payload));
73
64
  }
74
65
  } else {
75
- node.error("Homebridge not initialized - 1", this.msg);
76
- node.status({
77
- text: 'Homebridge not initialized -1',
78
- shape: 'ring',
79
- fill: 'red'
80
- });
66
+ this.handleError("Homebridge not initialized - 1");
81
67
  }
82
68
  } else {
83
- node.error("Payload should be an JSON object containing device characteristics and values, ie {\"On\":false, \"Brightness\":0 }\nValid values include: " + node.hbDevice.descriptions, this.msg);
84
- node.status({
85
- text: 'Invalid payload',
86
- shape: 'ring',
87
- fill: 'red'
88
- });
69
+ this.handleError(
70
+ "Payload should be a JSON object containing device characteristics and values, e.g., {\"On\":false, \"Brightness\":0 }"
71
+ );
89
72
  }
90
- });
91
-
92
- node.command = function (event) {
93
- // debug("hbResume received event: %s ->", node.fullName, event);
94
- // debug("hbResume - internals %s millis, old %s, event %s, previous %s", Date.now() - node.lastMessageTime, node.lastMessageValue, event.status, node.state);
95
- // Don't update for events originating from here
96
- // if Elapsed is greater than 5 seconds, update stored state
97
- // if Elapsed is less then 5, and lastMessage doesn't match event update stored state
98
-
99
- var payload = Object.assign({}, node.state);
100
-
101
- // debug("should be true", _getObjectDiff(payload, node.state).length);
102
-
103
- payload = Object.assign(payload, _convertHBcharactericToNode([event], node));
73
+ }
104
74
 
105
- // debug("should be false", _getObjectDiff(payload, node.state).length);
106
-
107
- debug("hbResume.event: %s %s -> %s", node.fullName, JSON.stringify(node.state), JSON.stringify(payload));
75
+ handleCommand(event) {
76
+ const payload = { ...this.state, ..._convertHBcharactericToNode([event], this) };
77
+ debug("hbResume.event: %s %s -> %s", this.fullName, JSON.stringify(this.state), JSON.stringify(payload));
108
78
 
109
79
  if (event.status === true && event.value !== undefined) {
110
- if ((Date.now() - node.lastMessageTime) > 5000) {
111
- debug("hbResume.update: %s - updating stored event >5", node.fullName, payload);
112
- node.state = JSON.parse(JSON.stringify(payload));
113
- } else if (_getObjectDiff(payload, node.lastMessageValue).length > 0) {
114
- // debug("hbResume - updating stored event !=", payload, node.lastMessageValue);
115
- // node.state = payload;
80
+ if (Date.now() - this.lastMessageTime > 5000) {
81
+ debug("hbResume.update: %s - updating stored event >5", this.fullName, payload);
82
+ this.state = JSON.parse(JSON.stringify(payload));
116
83
  }
117
84
  } else if (event.status === true) {
118
- node.status({
119
- text: 'connected',
120
- shape: 'dot',
121
- fill: 'green'
122
- });
85
+ this.updateStatus({ text: 'connected', shape: 'dot', fill: 'green' });
123
86
  } else {
124
- node.status({
125
- text: 'disconnected: ' + event.status,
126
- shape: 'ring',
127
- fill: 'red'
128
- });
87
+ this.updateStatus({ text: `disconnected: ${event.status}`, shape: 'ring', fill: 'red' });
129
88
  }
130
- };
89
+ }
90
+
91
+ handleDeviceRegistration() {
92
+ debug("hbResume.register:", this.fullName);
93
+ this.hbDevice = hbDevices.findDevice(this.device, { perms: 'pw' });
131
94
 
132
- node.conf.register(node, function () {
133
- debug("hbResume.register:", node.fullName);
134
- this.hbDevice = hbDevices.findDevice(node.device, {
135
- perms: 'pw'
136
- });
137
95
  if (this.hbDevice) {
138
- _status(node.device, node, {
139
- perms: 'pw'
140
- }, function (err, message) {
96
+ _status(this.device, this, { perms: 'pw' }, (err, message) => {
141
97
  if (!err) {
142
- node.state = _convertHBcharactericToNode(message.characteristics, node);
143
- debug("hbResume received: %s = %s", node.fullName, JSON.stringify(message.characteristics).slice(0, 80) + '...');
98
+ this.state = _convertHBcharactericToNode(message.characteristics, this);
99
+ debug("hbResume received: %s = %s", this.fullName, JSON.stringify(message.characteristics).slice(0, 80) + '...');
144
100
  } else {
145
- node.error(err);
101
+ this.error(err);
146
102
  }
147
103
  });
148
- node.hbDevice = this.hbDevice;
149
- node.deviceType = this.hbDevice.deviceType;
150
- // Register for events
151
- node.listener = node.command;
152
- node.eventName = [];
153
- // node.eventName = this.hbDevice.host + this.hbDevice.port + this.hbDevice.aid;
154
- // homebridge.on(this.hbDevice.host + this.hbDevice.port + this.hbDevice.aid, node.command);
155
- this.hbDevice.eventRegisters.forEach(function (event) {
156
- homebridge.on(node.hbDevice.id + event.aid + event.iid, node.command);
157
- node.eventName.push(node.hbDevice.id + event.aid + event.iid);
158
- });
159
- node.status({
160
- text: 'connected',
161
- shape: 'dot',
162
- fill: 'green'
104
+
105
+ this.deviceType = this.hbDevice.deviceType;
106
+ this.listener = this.command;
107
+ this.eventName = [];
108
+
109
+ this.hbDevice.eventRegisters.forEach((event) => {
110
+ homebridge.on(this.hbDevice.id + event.aid + event.iid, this.command);
111
+ this.eventName.push(this.hbDevice.id + event.aid + event.iid);
163
112
  });
164
- clearTimeout(node.timeout);
165
- node.timeout = setTimeout(function () {
166
- node.status({});
167
- }, 30 * 1000);
113
+
114
+ this.updateStatus({ text: 'connected', shape: 'dot', fill: 'green' });
115
+ this.resetTimeout(30000);
168
116
  } else {
169
- node.error("365:Can't find device " + node.device, null);
117
+ this.error(`Can't find device ${this.device}`);
170
118
  }
171
- }.bind(this));
119
+ }
120
+
121
+ updateStatus(status) {
122
+ this.status(status);
123
+ this.resetTimeout(10000);
124
+ }
125
+
126
+ resetTimeout(duration) {
127
+ clearTimeout(this.timeout);
128
+ this.timeout = setTimeout(() => this.status({}), duration);
129
+ }
130
+
131
+ handleError(message) {
132
+ this.error(message, this.msg);
133
+ this.updateStatus({ text: message, shape: 'ring', fill: 'red' });
134
+ }
135
+ }
172
136
 
173
- node.on('close', function (callback) {
174
- node.conf.deregister(node, callback);
175
- });
176
- }
137
+ module.exports = HbResumeNode;