node-red-contrib-homebridge-automation 0.1.12-beta.11 → 0.1.12-beta.12
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 +2 -2
- package/src/HAP-NodeRed.js +7 -121
- package/src/hbConfigNode.js +37 -36
- package/src/hbEventNode.js +98 -93
- package/src/hbResumeNode.js +176 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-homebridge-automation",
|
|
3
|
-
"version": "0.1.12-beta.
|
|
3
|
+
"version": "0.1.12-beta.12",
|
|
4
4
|
"description": "NodeRED Automation for HomeBridge",
|
|
5
5
|
"main": "src/HAP-NodeRed.js",
|
|
6
6
|
"scripts": {
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
],
|
|
63
63
|
"ext": "js,html",
|
|
64
64
|
"ignore": [],
|
|
65
|
-
"exec": "DEBUG=hapNodeRed ~/npm/bin/node-red -u test/node-red",
|
|
65
|
+
"exec": "npm run lint && DEBUG=hapNodeRed ~/npm/bin/node-red -u test/node-red",
|
|
66
66
|
"signal": "SIGTERM",
|
|
67
67
|
"env": {
|
|
68
68
|
"NODE_OPTIONS": "--trace-warnings"
|
package/src/HAP-NodeRed.js
CHANGED
|
@@ -3,6 +3,7 @@ var Queue = require('better-queue');
|
|
|
3
3
|
// var register = require('./lib/register.js');
|
|
4
4
|
|
|
5
5
|
const HBConfNode = require('./hbConfigNode');
|
|
6
|
+
const HbEventNode = require('./hbEventNode'); // Import the class
|
|
6
7
|
|
|
7
8
|
module.exports = function (RED) {
|
|
8
9
|
var evDevices = [];
|
|
@@ -54,129 +55,14 @@ module.exports = function (RED) {
|
|
|
54
55
|
* @return {type} description
|
|
55
56
|
*/
|
|
56
57
|
|
|
57
|
-
function
|
|
58
|
-
// debug("hbEvent", n);
|
|
58
|
+
function hbEventNode(n) {
|
|
59
59
|
RED.nodes.createNode(this, n);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
this
|
|
63
|
-
this.service = n.Service;
|
|
64
|
-
this.name = n.name;
|
|
65
|
-
this.fullName = n.name + ' - ' + n.Service;
|
|
66
|
-
this.sendInitialState = n.sendInitialState === true;
|
|
67
|
-
this.state = {};
|
|
68
|
-
|
|
69
|
-
var node = this;
|
|
70
|
-
|
|
71
|
-
node.command = function (event) {
|
|
72
|
-
// False messages can be received from accessories with multiple services
|
|
73
|
-
// if (Object.keys(_convertHBcharactericToNode(event, node)).length > 0) {
|
|
74
|
-
// debug("hbEvent", node.name, event);
|
|
75
|
-
if (event.status === true && event.value !== undefined) {
|
|
76
|
-
node.state = Object.assign(node.state, _convertHBcharactericToNode([event], node));
|
|
77
|
-
var msg = {
|
|
78
|
-
name: node.name,
|
|
79
|
-
payload: node.state,
|
|
80
|
-
Homebridge: node.hbDevice.homebridge,
|
|
81
|
-
Manufacturer: node.hbDevice.manufacturer,
|
|
82
|
-
Service: node.hbDevice.deviceType,
|
|
83
|
-
_device: node.device,
|
|
84
|
-
_confId: node.confId,
|
|
85
|
-
_rawEvent: event
|
|
86
|
-
};
|
|
87
|
-
node.status({
|
|
88
|
-
text: JSON.stringify(msg.payload).slice(0, 30) + '...',
|
|
89
|
-
shape: 'dot',
|
|
90
|
-
fill: 'green'
|
|
91
|
-
});
|
|
92
|
-
clearTimeout(node.timeout);
|
|
93
|
-
node.timeout = setTimeout(function () {
|
|
94
|
-
node.status({});
|
|
95
|
-
}, 10 * 1000);
|
|
96
|
-
node.send(msg);
|
|
97
|
-
} else if (event.status === true) {
|
|
98
|
-
node.status({
|
|
99
|
-
text: 'connected',
|
|
100
|
-
shape: 'dot',
|
|
101
|
-
fill: 'green'
|
|
102
|
-
});
|
|
103
|
-
} else {
|
|
104
|
-
node.status({
|
|
105
|
-
text: 'disconnected: ' + event.status,
|
|
106
|
-
shape: 'ring',
|
|
107
|
-
fill: 'red'
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
|
-
// };
|
|
112
|
-
|
|
113
|
-
node.conf.register(node, function () {
|
|
114
|
-
debug("hbEvent.register", node.fullName);
|
|
115
|
-
this.hbDevice = hbDevices.findDevice(node.device, {
|
|
116
|
-
perms: 'pr'
|
|
117
|
-
});
|
|
118
|
-
if (this.hbDevice) {
|
|
119
|
-
node.hbDevice = this.hbDevice;
|
|
120
|
-
node.deviceType = this.hbDevice.deviceType;
|
|
121
|
-
|
|
122
|
-
_status(node.device, node, {
|
|
123
|
-
perms: 'ev'
|
|
124
|
-
}, function (err, message) {
|
|
125
|
-
if (!err) {
|
|
126
|
-
node.state = _convertHBcharactericToNode(message.characteristics, node);
|
|
127
|
-
debug("hbEvent received: %s = %s", node.fullName, JSON.stringify(message.characteristics).slice(0, 80) + '...');
|
|
128
|
-
if (node.sendInitialState) {
|
|
129
|
-
var msg = {
|
|
130
|
-
name: node.name,
|
|
131
|
-
payload: node.state,
|
|
132
|
-
Homebridge: node.hbDevice.homebridge,
|
|
133
|
-
Manufacturer: node.hbDevice.manufacturer,
|
|
134
|
-
Service: node.hbDevice.deviceType,
|
|
135
|
-
_device: node.device,
|
|
136
|
-
_confId: node.confId,
|
|
137
|
-
_rawMessage: message,
|
|
138
|
-
};
|
|
139
|
-
node.status({
|
|
140
|
-
text: JSON.stringify(msg.payload).slice(0, 30) + '...',
|
|
141
|
-
shape: 'dot',
|
|
142
|
-
fill: 'green'
|
|
143
|
-
});
|
|
144
|
-
clearTimeout(node.timeout);
|
|
145
|
-
node.timeout = setTimeout(function () {
|
|
146
|
-
node.status({});
|
|
147
|
-
}, 10 * 1000);
|
|
148
|
-
node.send(msg);
|
|
149
|
-
}
|
|
150
|
-
} else {
|
|
151
|
-
node.error("hbEvent _status: error", node.fullName, err);
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
// Register for events
|
|
155
|
-
node.listener = node.command;
|
|
156
|
-
node.eventName = [];
|
|
157
|
-
// node.eventName = this.hbDevice.host + this.hbDevice.port + this.hbDevice.aid;
|
|
158
|
-
// debug("DEVICE", this.hbDevice);
|
|
159
|
-
this.hbDevice.eventRegisters.forEach(function (event) {
|
|
160
|
-
homebridge.on(node.hbDevice.id + event.aid + event.iid, node.command);
|
|
161
|
-
node.eventName.push(node.hbDevice.id + event.aid + event.iid);
|
|
162
|
-
});
|
|
163
|
-
// homebridge.on(this.hbDevice.host + this.hbDevice.port + this.hbDevice.aid, node.command);
|
|
164
|
-
node.status({
|
|
165
|
-
text: 'connected',
|
|
166
|
-
shape: 'dot',
|
|
167
|
-
fill: 'green'
|
|
168
|
-
});
|
|
169
|
-
} else {
|
|
170
|
-
node.error("197:Can't find device " + node.device, null);
|
|
171
|
-
}
|
|
172
|
-
}.bind(this));
|
|
173
|
-
|
|
174
|
-
node.on('close', function (callback) {
|
|
175
|
-
node.conf.deregister(node, callback);
|
|
176
|
-
});
|
|
60
|
+
|
|
61
|
+
// Create instance of HbEventNode class to handle events
|
|
62
|
+
new HbEventNode(this, n); // Pass current node and config object
|
|
177
63
|
}
|
|
178
64
|
|
|
179
|
-
RED.nodes.registerType("hb-event",
|
|
65
|
+
RED.nodes.registerType("hb-event", hbEventNode);
|
|
180
66
|
|
|
181
67
|
/**
|
|
182
68
|
* hbResume - description
|
|
@@ -199,7 +85,7 @@ module.exports = function (RED) {
|
|
|
199
85
|
* @return {type} description
|
|
200
86
|
*/
|
|
201
87
|
|
|
202
|
-
function
|
|
88
|
+
function hbResumeNode(n) {
|
|
203
89
|
RED.nodes.createNode(this, n);
|
|
204
90
|
this.conf = RED.nodes.getNode(n.conf);
|
|
205
91
|
this.confId = n.conf;
|
package/src/hbConfigNode.js
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
const HAPNodeJSClient = require('hap-node-client').HAPNodeJSClient;
|
|
2
2
|
const debug = require('debug')('hapNodeRed:hbConfigNode');
|
|
3
|
-
|
|
3
|
+
const { Homebridges } = require('./lib/Homebridges.js');
|
|
4
4
|
|
|
5
5
|
class HBConfNode {
|
|
6
|
-
constructor(
|
|
6
|
+
constructor(nodeConfig, RED) {
|
|
7
7
|
this.RED = RED;
|
|
8
|
-
this.username =
|
|
9
|
-
this.macAddress =
|
|
10
|
-
this.password =
|
|
8
|
+
this.username = nodeConfig.username;
|
|
9
|
+
this.macAddress = nodeConfig.macAddress || '';
|
|
10
|
+
this.password = nodeConfig.credentials.password;
|
|
11
11
|
this.users = {};
|
|
12
12
|
this.homebridge = null;
|
|
13
13
|
|
|
14
|
-
this.initHomebridge(
|
|
14
|
+
this.initHomebridge(nodeConfig);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
initHomebridge(
|
|
17
|
+
initHomebridge(nodeConfig) {
|
|
18
18
|
if (this.homebridge) {
|
|
19
19
|
if (this.macAddress) {
|
|
20
20
|
// Register additional PIN on existing instance
|
|
21
|
-
this.homebridge.RegisterPin(this.macAddress,
|
|
21
|
+
this.homebridge.RegisterPin(this.macAddress, nodeConfig.username);
|
|
22
22
|
}
|
|
23
23
|
} else {
|
|
24
24
|
this.homebridge = new HAPNodeJSClient({
|
|
25
|
-
pin:
|
|
25
|
+
pin: nodeConfig.username,
|
|
26
26
|
refresh: 900,
|
|
27
27
|
debug: false,
|
|
28
28
|
timeout: 20,
|
|
29
|
-
reqTimeout: 7000
|
|
29
|
+
reqTimeout: 7000,
|
|
30
30
|
});
|
|
31
31
|
this.homebridge.on('Ready', this.handleReady.bind(this));
|
|
32
32
|
}
|
|
@@ -36,58 +36,59 @@ class HBConfNode {
|
|
|
36
36
|
const hbDevices = new Homebridges(accessories);
|
|
37
37
|
debug('Discovered %s new evDevices', hbDevices.toList({ perms: 'ev' }).length);
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
const list = hbDevices.toList({ perms: 'ev' });
|
|
40
40
|
this.handleDuplicates(list);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
handleDuplicates(list) {
|
|
44
|
-
|
|
44
|
+
const deleteSeen = new Set();
|
|
45
45
|
|
|
46
|
-
for (
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
console.log("WARNING: Duplicate device name", endpoint.fullName);
|
|
46
|
+
for (const endpoint of list) {
|
|
47
|
+
if (deleteSeen.has(endpoint.fullName)) {
|
|
48
|
+
console.warn('WARNING: Duplicate device name', endpoint.fullName);
|
|
50
49
|
} else {
|
|
51
|
-
deleteSeen
|
|
50
|
+
deleteSeen.add(endpoint.fullName);
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
53
|
|
|
55
|
-
deleteSeen
|
|
54
|
+
deleteSeen.clear();
|
|
56
55
|
|
|
57
|
-
for (
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
console.log("ERROR: Parsing failed, duplicate uniqueID.", endpoint.fullName);
|
|
56
|
+
for (const endpoint of list) {
|
|
57
|
+
if (deleteSeen.has(endpoint.uniqueId)) {
|
|
58
|
+
console.error('ERROR: Parsing failed, duplicate uniqueID.', endpoint.fullName);
|
|
61
59
|
} else {
|
|
62
|
-
deleteSeen
|
|
60
|
+
deleteSeen.add(endpoint.uniqueId);
|
|
63
61
|
}
|
|
64
62
|
}
|
|
65
63
|
}
|
|
66
64
|
|
|
67
65
|
register(deviceNode, callback) {
|
|
68
|
-
debug(
|
|
66
|
+
debug('hbConf.register', deviceNode.fullName);
|
|
69
67
|
this.users[deviceNode.id] = deviceNode;
|
|
70
|
-
debug(
|
|
71
|
-
reqisterQueue.push(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
68
|
+
debug('Register %s -> %s', deviceNode.type, deviceNode.fullName);
|
|
69
|
+
reqisterQueue.push(
|
|
70
|
+
{
|
|
71
|
+
that: this,
|
|
72
|
+
device: deviceNode.device,
|
|
73
|
+
type: deviceNode.type,
|
|
74
|
+
name: deviceNode.name,
|
|
75
|
+
fullName: deviceNode.fullName,
|
|
76
|
+
node: this,
|
|
77
|
+
},
|
|
78
|
+
callback
|
|
79
|
+
);
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
deregister(deviceNode, callback) {
|
|
82
83
|
deviceNode.status({
|
|
83
84
|
text: 'disconnected',
|
|
84
85
|
shape: 'ring',
|
|
85
|
-
fill: 'red'
|
|
86
|
+
fill: 'red',
|
|
86
87
|
});
|
|
87
88
|
|
|
88
|
-
deviceNode.eventName
|
|
89
|
+
for (const event of deviceNode.eventName) {
|
|
89
90
|
this.homebridge.removeListener(event, deviceNode.listener);
|
|
90
|
-
}
|
|
91
|
+
}
|
|
91
92
|
|
|
92
93
|
callback();
|
|
93
94
|
}
|
package/src/hbEventNode.js
CHANGED
|
@@ -1,130 +1,135 @@
|
|
|
1
|
-
|
|
2
|
-
* hbEventNode - Node that listens to HomeKit Events, and sends message into NodeRED
|
|
3
|
-
*
|
|
4
|
-
* @param {type} n description
|
|
5
|
-
* @return {type} description
|
|
6
|
-
*/
|
|
1
|
+
const debug = require('debug')('hapNodeRed:hbEventNode');
|
|
7
2
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
3
|
+
class HbEventNode {
|
|
4
|
+
constructor(nodeConfig, RED) {
|
|
5
|
+
this.RED = RED;
|
|
6
|
+
this.node = nodeConfig;
|
|
7
|
+
this.conf = RED.nodes.getNode(nodeConfig.conf);
|
|
8
|
+
this.confId = nodeConfig.conf;
|
|
9
|
+
this.device = nodeConfig.device;
|
|
10
|
+
this.service = nodeConfig.Service;
|
|
11
|
+
this.name = nodeConfig.name;
|
|
12
|
+
this.fullName = `${nodeConfig.name} - ${nodeConfig.Service}`;
|
|
13
|
+
this.sendInitialState = nodeConfig.sendInitialState === true;
|
|
14
|
+
this.state = {};
|
|
19
15
|
|
|
20
|
-
|
|
16
|
+
this.init();
|
|
17
|
+
}
|
|
21
18
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
19
|
+
// Initialize the event handling logic
|
|
20
|
+
init() {
|
|
21
|
+
this.node.command = this.command.bind(this);
|
|
22
|
+
|
|
23
|
+
// Register the node with the HbConf class
|
|
24
|
+
this.conf.register(this.node, this.handleDeviceRegistration.bind(this));
|
|
25
|
+
|
|
26
|
+
// Clean up when the node is closed
|
|
27
|
+
this.node.on('close', (callback) => {
|
|
28
|
+
this.conf.deregister(this.node, callback);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Handle event command processing
|
|
33
|
+
command(event) {
|
|
26
34
|
if (event.status === true && event.value !== undefined) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
name: node.name,
|
|
30
|
-
payload:
|
|
31
|
-
Homebridge: node.hbDevice.homebridge,
|
|
32
|
-
Manufacturer: node.hbDevice.manufacturer,
|
|
33
|
-
Service: node.hbDevice.deviceType,
|
|
34
|
-
_device: node.device,
|
|
35
|
-
_confId: node.confId,
|
|
36
|
-
_rawEvent: event
|
|
35
|
+
this.state = Object.assign(this.state, _convertHBcharactericToNode([event], this.node));
|
|
36
|
+
const msg = {
|
|
37
|
+
name: this.node.name,
|
|
38
|
+
payload: this.state,
|
|
39
|
+
Homebridge: this.node.hbDevice.homebridge,
|
|
40
|
+
Manufacturer: this.node.hbDevice.manufacturer,
|
|
41
|
+
Service: this.node.hbDevice.deviceType,
|
|
42
|
+
_device: this.node.device,
|
|
43
|
+
_confId: this.node.confId,
|
|
44
|
+
_rawEvent: event,
|
|
37
45
|
};
|
|
38
|
-
node.status({
|
|
39
|
-
text: JSON.stringify(msg.payload).slice(0, 30)
|
|
46
|
+
this.node.status({
|
|
47
|
+
text: `${JSON.stringify(msg.payload).slice(0, 30)}...`,
|
|
40
48
|
shape: 'dot',
|
|
41
|
-
fill: 'green'
|
|
49
|
+
fill: 'green',
|
|
42
50
|
});
|
|
43
|
-
clearTimeout(node.timeout);
|
|
44
|
-
node.timeout = setTimeout(
|
|
45
|
-
node.status({});
|
|
51
|
+
clearTimeout(this.node.timeout);
|
|
52
|
+
this.node.timeout = setTimeout(() => {
|
|
53
|
+
this.node.status({});
|
|
46
54
|
}, 10 * 1000);
|
|
47
|
-
node.send(msg);
|
|
55
|
+
this.node.send(msg);
|
|
48
56
|
} else if (event.status === true) {
|
|
49
|
-
node.status({
|
|
57
|
+
this.node.status({
|
|
50
58
|
text: 'connected',
|
|
51
59
|
shape: 'dot',
|
|
52
|
-
fill: 'green'
|
|
60
|
+
fill: 'green',
|
|
53
61
|
});
|
|
54
62
|
} else {
|
|
55
|
-
node.status({
|
|
56
|
-
text:
|
|
63
|
+
this.node.status({
|
|
64
|
+
text: `disconnected: ${event.status}`,
|
|
57
65
|
shape: 'ring',
|
|
58
|
-
fill: 'red'
|
|
66
|
+
fill: 'red',
|
|
59
67
|
});
|
|
60
68
|
}
|
|
61
|
-
}
|
|
62
|
-
// };
|
|
69
|
+
}
|
|
63
70
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (this.hbDevice) {
|
|
70
|
-
node.
|
|
71
|
-
node.deviceType = this.hbDevice.deviceType;
|
|
71
|
+
// Handle device registration logic
|
|
72
|
+
handleDeviceRegistration() {
|
|
73
|
+
debug('hbEvent.register', this.node.fullName);
|
|
74
|
+
this.node.hbDevice = hbDevices.findDevice(this.node.device, { perms: 'pr' });
|
|
75
|
+
|
|
76
|
+
if (this.node.hbDevice) {
|
|
77
|
+
this.node.deviceType = this.node.hbDevice.deviceType;
|
|
72
78
|
|
|
73
|
-
_status(node.device, node, {
|
|
74
|
-
perms: 'ev'
|
|
75
|
-
}, function (err, message) {
|
|
79
|
+
_status(this.node.device, this.node, { perms: 'ev' }, (err, message) => {
|
|
76
80
|
if (!err) {
|
|
77
|
-
|
|
78
|
-
debug(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
81
|
+
this.state = _convertHBcharactericToNode(message.characteristics, this.node);
|
|
82
|
+
debug(
|
|
83
|
+
'hbEvent received: %s = %s',
|
|
84
|
+
this.node.fullName,
|
|
85
|
+
`${JSON.stringify(message.characteristics).slice(0, 80)}...`
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
if (this.sendInitialState) {
|
|
89
|
+
const msg = {
|
|
90
|
+
name: this.node.name,
|
|
91
|
+
payload: this.state,
|
|
92
|
+
Homebridge: this.node.hbDevice.homebridge,
|
|
93
|
+
Manufacturer: this.node.hbDevice.manufacturer,
|
|
94
|
+
Service: this.node.hbDevice.deviceType,
|
|
95
|
+
_device: this.node.device,
|
|
96
|
+
_confId: this.node.confId,
|
|
88
97
|
_rawMessage: message,
|
|
89
98
|
};
|
|
90
|
-
node.status({
|
|
91
|
-
text: JSON.stringify(msg.payload).slice(0, 30)
|
|
99
|
+
this.node.status({
|
|
100
|
+
text: `${JSON.stringify(msg.payload).slice(0, 30)}...`,
|
|
92
101
|
shape: 'dot',
|
|
93
|
-
fill: 'green'
|
|
102
|
+
fill: 'green',
|
|
94
103
|
});
|
|
95
|
-
clearTimeout(node.timeout);
|
|
96
|
-
node.timeout = setTimeout(
|
|
97
|
-
node.status({});
|
|
104
|
+
clearTimeout(this.node.timeout);
|
|
105
|
+
this.node.timeout = setTimeout(() => {
|
|
106
|
+
this.node.status({});
|
|
98
107
|
}, 10 * 1000);
|
|
99
|
-
node.send(msg);
|
|
108
|
+
this.node.send(msg);
|
|
100
109
|
}
|
|
101
110
|
} else {
|
|
102
|
-
node.error(
|
|
111
|
+
this.node.error('hbEvent _status: error', this.node.fullName, err);
|
|
103
112
|
}
|
|
104
113
|
});
|
|
114
|
+
|
|
105
115
|
// Register for events
|
|
106
|
-
node.listener = node.command;
|
|
107
|
-
node.eventName = [];
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
node.eventName.push(node.hbDevice.id + event.aid + event.iid);
|
|
116
|
+
this.node.listener = this.node.command;
|
|
117
|
+
this.node.eventName = [];
|
|
118
|
+
|
|
119
|
+
this.node.hbDevice.eventRegisters.forEach((event) => {
|
|
120
|
+
homebridge.on(this.node.hbDevice.id + event.aid + event.iid, this.node.command);
|
|
121
|
+
this.node.eventName.push(this.node.hbDevice.id + event.aid + event.iid);
|
|
113
122
|
});
|
|
114
|
-
|
|
115
|
-
node.status({
|
|
123
|
+
|
|
124
|
+
this.node.status({
|
|
116
125
|
text: 'connected',
|
|
117
126
|
shape: 'dot',
|
|
118
|
-
fill: 'green'
|
|
127
|
+
fill: 'green',
|
|
119
128
|
});
|
|
120
129
|
} else {
|
|
121
|
-
node.error(
|
|
130
|
+
this.node.error(`197:Can't find device ${this.node.device}`, null);
|
|
122
131
|
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
node.on('close', function (callback) {
|
|
126
|
-
node.conf.deregister(node, callback);
|
|
127
|
-
});
|
|
132
|
+
}
|
|
128
133
|
}
|
|
129
134
|
|
|
130
|
-
|
|
135
|
+
module.exports = HbEventNode;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
const debug = require('debug')('hapNodeRed:hbResumeNode');
|
|
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) {
|
|
21
|
+
this.msg = msg;
|
|
22
|
+
debug("hbResume.input: %s input", node.fullName, JSON.stringify(msg));
|
|
23
|
+
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);
|
|
27
|
+
|
|
28
|
+
if (message.characteristics.length > 0) {
|
|
29
|
+
var newMsg;
|
|
30
|
+
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
|
|
35
|
+
newMsg = {
|
|
36
|
+
name: node.name,
|
|
37
|
+
_device: node.device,
|
|
38
|
+
_confId: node.confId
|
|
39
|
+
};
|
|
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
|
+
} else {
|
|
47
|
+
// last msg was off, pass thru
|
|
48
|
+
node.state = JSON.parse(JSON.stringify(msg.payload));
|
|
49
|
+
newMsg = msg;
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
// True / Turn on
|
|
53
|
+
newMsg = msg;
|
|
54
|
+
}
|
|
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
|
|
73
|
+
}
|
|
74
|
+
} 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
|
+
});
|
|
81
|
+
}
|
|
82
|
+
} 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
|
+
});
|
|
89
|
+
}
|
|
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));
|
|
104
|
+
|
|
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));
|
|
108
|
+
|
|
109
|
+
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;
|
|
116
|
+
}
|
|
117
|
+
} else if (event.status === true) {
|
|
118
|
+
node.status({
|
|
119
|
+
text: 'connected',
|
|
120
|
+
shape: 'dot',
|
|
121
|
+
fill: 'green'
|
|
122
|
+
});
|
|
123
|
+
} else {
|
|
124
|
+
node.status({
|
|
125
|
+
text: 'disconnected: ' + event.status,
|
|
126
|
+
shape: 'ring',
|
|
127
|
+
fill: 'red'
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
node.conf.register(node, function () {
|
|
133
|
+
debug("hbResume.register:", node.fullName);
|
|
134
|
+
this.hbDevice = hbDevices.findDevice(node.device, {
|
|
135
|
+
perms: 'pw'
|
|
136
|
+
});
|
|
137
|
+
if (this.hbDevice) {
|
|
138
|
+
_status(node.device, node, {
|
|
139
|
+
perms: 'pw'
|
|
140
|
+
}, function (err, message) {
|
|
141
|
+
if (!err) {
|
|
142
|
+
node.state = _convertHBcharactericToNode(message.characteristics, node);
|
|
143
|
+
debug("hbResume received: %s = %s", node.fullName, JSON.stringify(message.characteristics).slice(0, 80) + '...');
|
|
144
|
+
} else {
|
|
145
|
+
node.error(err);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
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'
|
|
163
|
+
});
|
|
164
|
+
clearTimeout(node.timeout);
|
|
165
|
+
node.timeout = setTimeout(function () {
|
|
166
|
+
node.status({});
|
|
167
|
+
}, 30 * 1000);
|
|
168
|
+
} else {
|
|
169
|
+
node.error("365:Can't find device " + node.device, null);
|
|
170
|
+
}
|
|
171
|
+
}.bind(this));
|
|
172
|
+
|
|
173
|
+
node.on('close', function (callback) {
|
|
174
|
+
node.conf.deregister(node, callback);
|
|
175
|
+
});
|
|
176
|
+
}
|