node-red-contrib-homebridge-automation 0.1.12-beta.1 → 0.1.12-beta.10
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/.eslintrc.js +1 -1
- package/README.md +1 -1
- package/package.json +15 -6
- package/src/HAP-NodeRed.js +61 -59
- package/src/lib/Accessory.js +12 -5
- package/test/test_spec.js +1 -1
package/.eslintrc.js
CHANGED
package/README.md
CHANGED
|
@@ -60,7 +60,7 @@ The above Node-RED Flow, turns on my 'Outside Office' light when the powder room
|
|
|
60
60
|
* [To start Node-RED in DEBUG mode, and output Homebridge-Automation debug logs start Node-RED like this.](#to-start-node-red-in-debug-mode-and-output-homebridge-automation-debug-logs-start-node-red-like-this)
|
|
61
61
|
|
|
62
62
|
<!-- Created by https://github.com/ekalinin/github-markdown-toc -->
|
|
63
|
-
<!-- Added by: runner, at:
|
|
63
|
+
<!-- Added by: runner, at: Mon Jul 8 00:34:52 UTC 2024 -->
|
|
64
64
|
|
|
65
65
|
<!--te-->
|
|
66
66
|
|
package/package.json
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-homebridge-automation",
|
|
3
|
-
"version": "0.1.12-beta.
|
|
3
|
+
"version": "0.1.12-beta.10",
|
|
4
4
|
"description": "NodeRED Automation for HomeBridge",
|
|
5
5
|
"main": "src/HAP-NodeRed.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"api": "documentation build HAP-NodeRed.js -f md --config docs/documentation.yml > docs/API.md",
|
|
8
|
-
"document": "./gh-md-toc --insert
|
|
9
|
-
"watch": "nodemon"
|
|
8
|
+
"document": "./gh-md-toc --insert --no-backup --hide-footer README.md",
|
|
9
|
+
"watch": "nodemon",
|
|
10
|
+
"coverage": "nyc npm t",
|
|
11
|
+
"format": "prettier --write {.,test}/*.js *.html *.md",
|
|
12
|
+
"lint": "eslint {.,test}/*.js",
|
|
13
|
+
"test": "mocha \"test/**/*_spec.js\""
|
|
10
14
|
},
|
|
11
15
|
"keywords": [
|
|
12
16
|
"node-red",
|
|
@@ -23,9 +27,14 @@
|
|
|
23
27
|
},
|
|
24
28
|
"devDependencies": {
|
|
25
29
|
"@types/node-red": "^0.20.7",
|
|
30
|
+
"@types/jest": "^29.5.12",
|
|
26
31
|
"documentation": "14.0.3",
|
|
27
|
-
"eslint": "^
|
|
28
|
-
"eslint-
|
|
32
|
+
"eslint": "^8.57.0",
|
|
33
|
+
"eslint-config-airbnb-typescript": "^18.0.0",
|
|
34
|
+
"eslint-plugin-import": "^2.29.1",
|
|
35
|
+
"eslint-plugin-import-newlines": "^1.4.0",
|
|
36
|
+
"eslint-plugin-jest": "^28.6.0",
|
|
37
|
+
"eslint-plugin-sort-exports": "^0.9.1",
|
|
29
38
|
"mocha": "^10.6.0",
|
|
30
39
|
"node-red": "^4.0.2",
|
|
31
40
|
"node-red-node-test-helper": "^0.3.4",
|
|
@@ -52,7 +61,7 @@
|
|
|
52
61
|
],
|
|
53
62
|
"ext": "js,html",
|
|
54
63
|
"ignore": [],
|
|
55
|
-
"exec": "DEBUG=hapNodeRed ~/npm/bin/node-red",
|
|
64
|
+
"exec": "DEBUG=hapNodeRed,hapNodeJSClient ~/npm/bin/node-red",
|
|
56
65
|
"signal": "SIGTERM",
|
|
57
66
|
"env": {
|
|
58
67
|
"NODE_OPTIONS": "--trace-warnings"
|
package/src/HAP-NodeRed.js
CHANGED
|
@@ -180,7 +180,7 @@ module.exports = function (RED) {
|
|
|
180
180
|
node.command = function (event) {
|
|
181
181
|
// False messages can be received from accessories with multiple services
|
|
182
182
|
// if (Object.keys(_convertHBcharactericToNode(event, node)).length > 0) {
|
|
183
|
-
debug("hbEvent", node.name, event);
|
|
183
|
+
// debug("hbEvent", node.name, event);
|
|
184
184
|
if (event.status === true && event.value !== undefined) {
|
|
185
185
|
node.state = Object.assign(node.state, _convertHBcharactericToNode([event], node));
|
|
186
186
|
var msg = {
|
|
@@ -194,7 +194,7 @@ module.exports = function (RED) {
|
|
|
194
194
|
_rawEvent: event
|
|
195
195
|
};
|
|
196
196
|
node.status({
|
|
197
|
-
text: JSON.stringify(msg.payload),
|
|
197
|
+
text: JSON.stringify(msg.payload).slice(0, 30) + '...',
|
|
198
198
|
shape: 'dot',
|
|
199
199
|
fill: 'green'
|
|
200
200
|
});
|
|
@@ -233,7 +233,7 @@ module.exports = function (RED) {
|
|
|
233
233
|
}, function (err, message) {
|
|
234
234
|
if (!err) {
|
|
235
235
|
node.state = _convertHBcharactericToNode(message.characteristics, node);
|
|
236
|
-
debug("hbEvent received: %s = %s", node.fullName, JSON.stringify(message.characteristics),
|
|
236
|
+
debug("hbEvent received: %s = %s", node.fullName, JSON.stringify(message.characteristics).slice(0, 80) + '...');
|
|
237
237
|
if (node.sendInitialState) {
|
|
238
238
|
var msg = {
|
|
239
239
|
name: node.name,
|
|
@@ -246,7 +246,7 @@ module.exports = function (RED) {
|
|
|
246
246
|
_rawMessage: message,
|
|
247
247
|
};
|
|
248
248
|
node.status({
|
|
249
|
-
text: JSON.stringify(msg.payload),
|
|
249
|
+
text: JSON.stringify(msg.payload).slice(0, 30) + '...',
|
|
250
250
|
shape: 'dot',
|
|
251
251
|
fill: 'green'
|
|
252
252
|
});
|
|
@@ -366,7 +366,7 @@ module.exports = function (RED) {
|
|
|
366
366
|
}, newMsg));
|
|
367
367
|
debug("hbResume.input: %s output", node.fullName, JSON.stringify(newMsg));
|
|
368
368
|
node.status({
|
|
369
|
-
text: JSON.stringify(newMsg.payload),
|
|
369
|
+
text: JSON.stringify(newMsg.payload).slice(0, 30) + '...',
|
|
370
370
|
shape: 'dot',
|
|
371
371
|
fill: 'green'
|
|
372
372
|
});
|
|
@@ -380,9 +380,9 @@ module.exports = function (RED) {
|
|
|
380
380
|
node.lastPayload = JSON.parse(JSON.stringify(msg.payload)); // store value not reference
|
|
381
381
|
}
|
|
382
382
|
} else {
|
|
383
|
-
node.error("Homebridge not initialized", this.msg);
|
|
383
|
+
node.error("Homebridge not initialized - 1", this.msg);
|
|
384
384
|
node.status({
|
|
385
|
-
text: 'Homebridge not initialized',
|
|
385
|
+
text: 'Homebridge not initialized -1',
|
|
386
386
|
shape: 'ring',
|
|
387
387
|
fill: 'red'
|
|
388
388
|
});
|
|
@@ -448,7 +448,7 @@ module.exports = function (RED) {
|
|
|
448
448
|
}, function (err, message) {
|
|
449
449
|
if (!err) {
|
|
450
450
|
node.state = _convertHBcharactericToNode(message.characteristics, node);
|
|
451
|
-
debug("hbResume received: %s = %s", node.fullName, JSON.stringify(message.characteristics),
|
|
451
|
+
debug("hbResume received: %s = %s", node.fullName, JSON.stringify(message.characteristics).slice(0, 80) + '...');
|
|
452
452
|
} else {
|
|
453
453
|
node.error(err);
|
|
454
454
|
}
|
|
@@ -505,37 +505,23 @@ module.exports = function (RED) {
|
|
|
505
505
|
|
|
506
506
|
node.on('input', function (msg) {
|
|
507
507
|
this.msg = msg;
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
node.status({
|
|
523
|
-
text: error,
|
|
524
|
-
shape: 'ring',
|
|
525
|
-
fill: 'red'
|
|
526
|
-
});
|
|
527
|
-
node.error(error, this.msg);
|
|
528
|
-
return;
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
_control.call(this, node, device, msg.payload, function (err, data) {
|
|
532
|
-
// debug('hbControl [%s] - [%s]', err, data); // Images produce alot of noise
|
|
533
|
-
if (!err && data && (device.type == '00000110' || device.type == '00000111')) {
|
|
534
|
-
// debug('hbControl', err, data); // Images produce alot of noise
|
|
535
|
-
const msg = {};
|
|
508
|
+
_control.call(this, node, msg.payload, function (err, data) {
|
|
509
|
+
// debug('hbControl complete [%s] - [%s]', node, node.hbDevice); // Images produce alot of noise
|
|
510
|
+
if (!err && data && (node.deviceType == '00000110' || node.deviceType == '00000111')) {
|
|
511
|
+
const msg = {
|
|
512
|
+
name: node.name,
|
|
513
|
+
payload: node.state,
|
|
514
|
+
_device: node.device,
|
|
515
|
+
_confId: node.confId
|
|
516
|
+
};
|
|
517
|
+
if (node.hbDevice) {
|
|
518
|
+
msg.Homebridge = node.hbDevice.homebridge;
|
|
519
|
+
msg.Manufacturer = node.hbDevice.manufacturer;
|
|
520
|
+
msg.Service = node.hbDevice.deviceType;
|
|
521
|
+
}
|
|
536
522
|
msg.payload = data;
|
|
537
523
|
node.send(msg);
|
|
538
|
-
} else {
|
|
524
|
+
} else if (err) {
|
|
539
525
|
node.error(err, this.msg);
|
|
540
526
|
}
|
|
541
527
|
}.bind(this));
|
|
@@ -547,13 +533,18 @@ module.exports = function (RED) {
|
|
|
547
533
|
});
|
|
548
534
|
|
|
549
535
|
node.conf.register(node, function () {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
536
|
+
debug("hbControl.register:", node.fullName);
|
|
537
|
+
this.hbDevice = hbDevices.findDevice(node.device);
|
|
538
|
+
// console.log('hbControl Register', this.hbDevice)
|
|
539
|
+
if (this.hbDevice) {
|
|
540
|
+
node.hbDevice = this.hbDevice;
|
|
541
|
+
node.deviceType = this.hbDevice.type;
|
|
542
|
+
// Register for events
|
|
543
|
+
node.listener = node.command;
|
|
544
|
+
// node.eventName = this.hbDevice.host + this.hbDevice.port + this.hbDevice.aid;
|
|
545
|
+
} else {
|
|
546
|
+
node.error("437:Can't find device " + node.device, null);
|
|
547
|
+
// this.error("Missing device " + node.device);
|
|
557
548
|
}
|
|
558
549
|
});
|
|
559
550
|
}
|
|
@@ -599,7 +590,7 @@ module.exports = function (RED) {
|
|
|
599
590
|
perms: 'pr'
|
|
600
591
|
}, function (err, message) {
|
|
601
592
|
if (!err) {
|
|
602
|
-
debug("hbStatus received: %s = %s", JSON.stringify(node.fullName), JSON.stringify(message), JSON.stringify(node.hbDevice));
|
|
593
|
+
debug("hbStatus received: %s = %s", JSON.stringify(node.fullName), JSON.stringify(message).slice(0, 80) + '...', JSON.stringify(node.hbDevice));
|
|
603
594
|
this.msg.name = node.name;
|
|
604
595
|
this.msg._rawMessage = message;
|
|
605
596
|
this.msg.payload = _convertHBcharactericToNode(message.characteristics, node);
|
|
@@ -612,7 +603,7 @@ module.exports = function (RED) {
|
|
|
612
603
|
this.msg._confId = node.confId;
|
|
613
604
|
}
|
|
614
605
|
node.status({
|
|
615
|
-
text: JSON.stringify(this.msg.payload),
|
|
606
|
+
text: JSON.stringify(this.msg.payload).slice(0, 30) + '...',
|
|
616
607
|
shape: 'dot',
|
|
617
608
|
fill: 'green'
|
|
618
609
|
});
|
|
@@ -656,7 +647,7 @@ module.exports = function (RED) {
|
|
|
656
647
|
});
|
|
657
648
|
|
|
658
649
|
RED.httpAdmin.get('/hap-device/evDevices/:id', RED.auth.needsPermission('hb-event.read'), function (req, res) {
|
|
659
|
-
if (evDevices) {
|
|
650
|
+
if (evDevices && hbDevices) {
|
|
660
651
|
debug("evDevices", hbDevices.toList({
|
|
661
652
|
perms: 'ev'
|
|
662
653
|
}).length);
|
|
@@ -815,6 +806,9 @@ module.exports = function (RED) {
|
|
|
815
806
|
// debug("_status", new Error(), hbDevices);
|
|
816
807
|
var error;
|
|
817
808
|
try {
|
|
809
|
+
if (!hbDevices) {
|
|
810
|
+
throw new Error('hbDevices not initialized');
|
|
811
|
+
}
|
|
818
812
|
var device = hbDevices.findDevice(node.device, perms);
|
|
819
813
|
if (device) {
|
|
820
814
|
// debug("device.type", device.type);
|
|
@@ -828,7 +822,7 @@ module.exports = function (RED) {
|
|
|
828
822
|
};
|
|
829
823
|
debug("_status Control %s -> %s", device.id, JSON.stringify(message));
|
|
830
824
|
homebridge.HAPresourceByDeviceID(device.id, JSON.stringify(message), function (err, status) {
|
|
831
|
-
debug("status", err);
|
|
825
|
+
// debug("status", err);
|
|
832
826
|
if (!err) {
|
|
833
827
|
debug("_status Controlled %s:%s ->", device.host, device.port);
|
|
834
828
|
node.status({
|
|
@@ -894,8 +888,8 @@ module.exports = function (RED) {
|
|
|
894
888
|
callback(error);
|
|
895
889
|
} // end of device if
|
|
896
890
|
} catch (err) {
|
|
897
|
-
debug('_status', err);
|
|
898
|
-
error = "Homebridge not initialized";
|
|
891
|
+
// debug('_status', err);
|
|
892
|
+
error = "Homebridge not initialized -2";
|
|
899
893
|
node.status({
|
|
900
894
|
text: error,
|
|
901
895
|
shape: 'ring',
|
|
@@ -915,25 +909,33 @@ module.exports = function (RED) {
|
|
|
915
909
|
* @return {type} description
|
|
916
910
|
*/
|
|
917
911
|
|
|
918
|
-
function _control(node,
|
|
912
|
+
function _control(node, payload, callback) {
|
|
919
913
|
try {
|
|
914
|
+
if (!hbDevices) {
|
|
915
|
+
throw new Error('hbDevices not initialized');
|
|
916
|
+
}
|
|
917
|
+
var device = hbDevices.findDevice(node.device, {
|
|
918
|
+
perms: 'pw'
|
|
919
|
+
});
|
|
920
920
|
if (device) {
|
|
921
921
|
var message;
|
|
922
|
+
// console.log('device.type', device.type)
|
|
922
923
|
switch (device.type) {
|
|
923
924
|
case "00000110": // Camera RTPStream Management
|
|
924
925
|
case "00000111": // Camera Control
|
|
925
926
|
message = {
|
|
926
927
|
"resource-type": "image",
|
|
927
928
|
"image-width": 1920,
|
|
928
|
-
"image-height": 1080
|
|
929
|
+
"image-height": 1080,
|
|
930
|
+
"aid": node.hbDevice.aid
|
|
929
931
|
};
|
|
930
|
-
debug("Control %s ->", device.id, JSON.stringify(message));
|
|
932
|
+
debug("Control %s ->", device.id, node.fullName, JSON.stringify(message));
|
|
931
933
|
homebridge.HAPresourceByDeviceID(device.id, JSON.stringify(message), function (err, status) {
|
|
932
934
|
if (!err) {
|
|
933
|
-
debug("Controlled %s ->", device.id, JSON.stringify(payload));
|
|
934
|
-
debug("Payload %s ->", device.id, status);
|
|
935
|
+
// debug("Controlled %s ->", device.id, JSON.stringify(payload));
|
|
936
|
+
// debug("Payload %s ->", device.id, status);
|
|
935
937
|
node.status({
|
|
936
|
-
text: JSON.stringify(payload),
|
|
938
|
+
text: JSON.stringify(payload).slice(0, 30) + '...',
|
|
937
939
|
shape: 'dot',
|
|
938
940
|
fill: 'green'
|
|
939
941
|
});
|
|
@@ -963,7 +965,7 @@ module.exports = function (RED) {
|
|
|
963
965
|
if (!err && status && status.characteristics[0].status === 0) {
|
|
964
966
|
debug("Controlled %s ->", device.id, JSON.stringify(status));
|
|
965
967
|
node.status({
|
|
966
|
-
text: JSON.stringify(payload),
|
|
968
|
+
text: JSON.stringify(payload).slice(0, 30) + '...',
|
|
967
969
|
shape: 'dot',
|
|
968
970
|
fill: 'green'
|
|
969
971
|
});
|
|
@@ -975,7 +977,7 @@ module.exports = function (RED) {
|
|
|
975
977
|
} else if (!err) {
|
|
976
978
|
debug("Controlled %s ->", device.id, payload);
|
|
977
979
|
node.status({
|
|
978
|
-
text: JSON.stringify(payload),
|
|
980
|
+
text: JSON.stringify(payload).slice(0, 30) + '...',
|
|
979
981
|
shape: 'dot',
|
|
980
982
|
fill: 'green'
|
|
981
983
|
});
|
|
@@ -1028,7 +1030,7 @@ module.exports = function (RED) {
|
|
|
1028
1030
|
callback(error);
|
|
1029
1031
|
}
|
|
1030
1032
|
} catch (err) {
|
|
1031
|
-
var error = "Homebridge not initialized";
|
|
1033
|
+
var error = "Homebridge not initialized - 3 "+ err;
|
|
1032
1034
|
node.status({
|
|
1033
1035
|
text: error,
|
|
1034
1036
|
shape: 'ring',
|
package/src/lib/Accessory.js
CHANGED
|
@@ -17,14 +17,21 @@ function Accessory(devices, context) {
|
|
|
17
17
|
this.homebridge = context.homebridge;
|
|
18
18
|
this.id = context.id;
|
|
19
19
|
this.services = [];
|
|
20
|
-
devices.services.forEach(function(element) {
|
|
20
|
+
devices.services.forEach(function (element) {
|
|
21
21
|
// debug("Service", element);
|
|
22
22
|
switch (element.type.substring(0, 8)) {
|
|
23
23
|
case "0000003E": // Accessory Information
|
|
24
24
|
this.info = information(element.characteristics);
|
|
25
25
|
break;
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
case "00000110": // Camera RTPStream Management generates duplicates
|
|
27
|
+
var service = new Service(element, this);
|
|
28
|
+
// console.log('services', this.services);
|
|
29
|
+
if (this.services.some(e => e.type === '00000110')) {
|
|
30
|
+
|
|
31
|
+
} else {
|
|
32
|
+
this.services.push(service);
|
|
33
|
+
}
|
|
34
|
+
break;
|
|
28
35
|
case "000000D9": // Input Source from webosTV has a dummy input source
|
|
29
36
|
var service = new Service(element, this);
|
|
30
37
|
if (service.name !== "dummy") {
|
|
@@ -39,7 +46,7 @@ function Accessory(devices, context) {
|
|
|
39
46
|
// debug("Info", this.info);
|
|
40
47
|
}
|
|
41
48
|
|
|
42
|
-
Accessory.prototype.toList = function(context) {
|
|
49
|
+
Accessory.prototype.toList = function (context) {
|
|
43
50
|
var list = [];
|
|
44
51
|
// debug("toList", context);
|
|
45
52
|
context.aid = this.aid;
|
|
@@ -109,7 +116,7 @@ Accessory.prototype.toList = function(context) {
|
|
|
109
116
|
|
|
110
117
|
function information(characteristics) {
|
|
111
118
|
var result = {};
|
|
112
|
-
characteristics.forEach(function(characteristic) {
|
|
119
|
+
characteristics.forEach(function (characteristic) {
|
|
113
120
|
if (characteristic.description) {
|
|
114
121
|
var key = characteristic.description.replace(/ /g, '').replace(/\./g, '_');
|
|
115
122
|
result[key] = characteristic.value;
|
package/test/test_spec.js
CHANGED
|
@@ -5,7 +5,7 @@ var helper = require('node-red-node-test-helper');
|
|
|
5
5
|
helper.init(require.resolve('node-red'), { userDir: os.tmpdir() });
|
|
6
6
|
|
|
7
7
|
var flows = require('./flows');
|
|
8
|
-
var hapNode = require('../HAP-NodeRed.js');
|
|
8
|
+
var hapNode = require('../src/HAP-NodeRed.js');
|
|
9
9
|
|
|
10
10
|
describe('HAP node', function () {
|
|
11
11
|
before(function (done) {
|