node-red-contrib-homebridge-automation 0.1.12-beta.39 → 0.1.12-beta.40
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 +1 -0
- package/package.json +3 -5
- package/src/hbConfigNode.js +10 -12
- package/src/hbConfigNode.test.js +0 -185
- package/src/lib/logger.js +0 -31
package/README.md
CHANGED
|
@@ -183,6 +183,7 @@ With a plugin, you can see if it supports Real Time events, by opening the Home
|
|
|
183
183
|
### Dec 15, 2024 - Version 0.2.0
|
|
184
184
|
|
|
185
185
|
- Major code base refresh, and migration from hap-node-client to hap-client ( Potential fix for #120 )
|
|
186
|
+
- Testing and Development was completed on Node-RED version: v4.0.2 and Node.js version: v20.18.1
|
|
186
187
|
|
|
187
188
|
# Backlog / Roadmap
|
|
188
189
|
|
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.40",
|
|
4
4
|
"description": "NodeRED Automation for HomeBridge",
|
|
5
5
|
"main": "src/HAP-NodeRed.js",
|
|
6
6
|
"scripts": {
|
|
@@ -36,15 +36,13 @@
|
|
|
36
36
|
"node-red": "^4.0.2",
|
|
37
37
|
"node-red-node-test-helper": "^0.3.4",
|
|
38
38
|
"nodemon": "^3.1.4",
|
|
39
|
-
"nyc": "^17.0.0",
|
|
40
|
-
"prettier": "^3.3.2",
|
|
41
39
|
"rimraf": "^6.0.1",
|
|
42
40
|
"semver": "^7.6.2"
|
|
43
41
|
},
|
|
44
42
|
"dependencies": {
|
|
45
43
|
"better-queue": ">=3.8.12",
|
|
46
44
|
"debug": "^4.3.5",
|
|
47
|
-
"@homebridge/hap-client": "2.0.5-beta.
|
|
45
|
+
"@homebridge/hap-client": "2.0.5-beta.21"
|
|
48
46
|
},
|
|
49
47
|
"author": "NorthernMan54",
|
|
50
48
|
"license": "ISC",
|
|
@@ -58,7 +56,7 @@
|
|
|
58
56
|
],
|
|
59
57
|
"ext": "js,html",
|
|
60
58
|
"ignore": [],
|
|
61
|
-
"exec": "DEBUG=hapNodeRed* ~/npm/bin/node-red -u test/node-red",
|
|
59
|
+
"exec": "DEBUG=hapNodeRed* ~/npm/bin/node-red -v -u test/node-red",
|
|
62
60
|
"signal": "SIGTERM",
|
|
63
61
|
"env": {
|
|
64
62
|
"NODE_OPTIONS": "--trace-warnings"
|
package/src/hbConfigNode.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const { HapClient } = require('@homebridge/hap-client');
|
|
2
2
|
const debug = require('debug')('hapNodeRed:hbConfigNode');
|
|
3
|
-
const { Log } = require('./lib/logger.js');
|
|
4
3
|
|
|
5
4
|
class HBConfigNode {
|
|
6
5
|
constructor(config, RED) {
|
|
@@ -16,14 +15,13 @@ class HBConfigNode {
|
|
|
16
15
|
this.ctDevices = [];
|
|
17
16
|
this.hbDevices = [];
|
|
18
17
|
this.clientNodes = [];
|
|
19
|
-
this.log = new Log(console, true);
|
|
18
|
+
// this.log = new Log(console, true);
|
|
20
19
|
this.discoveryTimeout = null;
|
|
21
20
|
|
|
22
21
|
// Initialize HAP client
|
|
23
22
|
this.hapClient = new HapClient({
|
|
24
23
|
config: { debug: false },
|
|
25
|
-
pin: config.username
|
|
26
|
-
logger: this.log,
|
|
24
|
+
pin: config.username
|
|
27
25
|
});
|
|
28
26
|
|
|
29
27
|
this.hapClient.on('instance-discovered', this.waitForNoMoreDiscoveries);
|
|
@@ -42,7 +40,7 @@ class HBConfigNode {
|
|
|
42
40
|
if (!this.refreshInProcess) {
|
|
43
41
|
|
|
44
42
|
this.monitor.finish();
|
|
45
|
-
this.
|
|
43
|
+
this.debug('Monitor reported homebridge stability issues, refreshing devices');
|
|
46
44
|
this.hapClient.on('instance-discovered', this.waitForNoMoreDiscoveries);
|
|
47
45
|
this.hapClient.resetInstancePool();
|
|
48
46
|
this.waitForNoMoreDiscoveries();
|
|
@@ -56,7 +54,7 @@ class HBConfigNode {
|
|
|
56
54
|
if (!this.discoveryTimeout) {
|
|
57
55
|
clearTimeout(this.discoveryTimeout);
|
|
58
56
|
this.discoveryTimeout = setTimeout(() => {
|
|
59
|
-
this.
|
|
57
|
+
this.debug('No more instances discovered, publishing services');
|
|
60
58
|
this.hapClient.removeListener('instance-discovered', this.waitForNoMoreDiscoveries);
|
|
61
59
|
this.handleReady();
|
|
62
60
|
this.discoveryTimeout = null;
|
|
@@ -81,7 +79,7 @@ class HBConfigNode {
|
|
|
81
79
|
|
|
82
80
|
this.evDevices = this.toList({ perms: 'ev' });
|
|
83
81
|
this.ctDevices = this.toList({ perms: 'pw' });
|
|
84
|
-
this.log
|
|
82
|
+
this.log(`Devices initialized: evDevices: ${this.evDevices.length}, ctDevices: ${this.ctDevices.length}`);
|
|
85
83
|
this.handleDuplicates(this.evDevices);
|
|
86
84
|
this.connectClientNodes();
|
|
87
85
|
}
|
|
@@ -117,10 +115,10 @@ class HBConfigNode {
|
|
|
117
115
|
const { fullName, uniqueId } = endpoint;
|
|
118
116
|
|
|
119
117
|
if (seen.has(fullName)) {
|
|
120
|
-
this.
|
|
118
|
+
this.warn(`Duplicate device name detected: ${fullName}`);
|
|
121
119
|
}
|
|
122
120
|
if (seen.has(uniqueId)) {
|
|
123
|
-
this.
|
|
121
|
+
this.error(`Duplicate uniqueId detected: ${uniqueId}`);
|
|
124
122
|
}
|
|
125
123
|
|
|
126
124
|
seen.set(fullName, true);
|
|
@@ -148,7 +146,7 @@ class HBConfigNode {
|
|
|
148
146
|
clientNode.emit('hbReady', matchedDevice);
|
|
149
147
|
debug('_Registered: %s type: %s', matchedDevice.type, matchedDevice.serviceName, matchedDevice.instance);
|
|
150
148
|
} else {
|
|
151
|
-
|
|
149
|
+
this.error(`ERROR: Device registration failed ${clientNode.name}`);
|
|
152
150
|
}
|
|
153
151
|
};
|
|
154
152
|
|
|
@@ -200,7 +198,7 @@ class HBConfigNode {
|
|
|
200
198
|
disconnectClientNodes(instance) {
|
|
201
199
|
debug('disconnectClientNodes', `${instance.ipAddress}:${instance.port}`);
|
|
202
200
|
const clientNodes = Object.values(this.clientNodes).filter(clientNode => {
|
|
203
|
-
return `${clientNode.hbDevice
|
|
201
|
+
return `${clientNode.hbDevice?.instance.ipAddress}:${clientNode.hbDevice?.instance.port}` === `${instance.ipAddress}:${instance.port}`;
|
|
204
202
|
});
|
|
205
203
|
|
|
206
204
|
clientNodes.forEach(clientNode => {
|
|
@@ -212,7 +210,7 @@ class HBConfigNode {
|
|
|
212
210
|
reconnectClientNodes(instance) {
|
|
213
211
|
debug('reconnectClientNodes', `${instance.ipAddress}:${instance.port}`);
|
|
214
212
|
const clientNodes = Object.values(this.clientNodes).filter(clientNode => {
|
|
215
|
-
return `${clientNode.hbDevice
|
|
213
|
+
return `${clientNode.hbDevice?.instance.ipAddress}:${clientNode.hbDevice?.instance.port}` === `${instance.ipAddress}:${instance.port}`;
|
|
216
214
|
});
|
|
217
215
|
|
|
218
216
|
clientNodes.forEach(clientNode => {
|
package/src/hbConfigNode.test.js
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
const debug = require('debug')('hapNodeRed:JEST');
|
|
2
|
-
|
|
3
|
-
const HBConfigNode = require('./hbConfigNode.js');
|
|
4
|
-
|
|
5
|
-
describe("toList", () => {
|
|
6
|
-
var hbConfigNode;
|
|
7
|
-
createNode = function () {
|
|
8
|
-
};
|
|
9
|
-
beforeAll(async () => {
|
|
10
|
-
// eslint-disable-next-line no-console
|
|
11
|
-
console.log('init');
|
|
12
|
-
hbConfigNode = new HBConfigNode({ jest: true });
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
test("should return an empty array when inputs is empty", () => {
|
|
16
|
-
const inputs = [];
|
|
17
|
-
const perms = [];
|
|
18
|
-
const result = hbConfigNode.toList(inputs, perms);
|
|
19
|
-
expect(result).toEqual([]);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
test("should map inputs to the expected output format", () => {
|
|
23
|
-
const inputs = [
|
|
24
|
-
{
|
|
25
|
-
"aid": 167,
|
|
26
|
-
"iid": 8,
|
|
27
|
-
"uuid": "00000040-0000-1000-8000-0026BB765291",
|
|
28
|
-
"type": "Fan",
|
|
29
|
-
"humanType": "Fan",
|
|
30
|
-
"serviceName": "Bunkie Fan",
|
|
31
|
-
"serviceCharacteristics": [
|
|
32
|
-
{
|
|
33
|
-
"aid": 167,
|
|
34
|
-
"iid": 10,
|
|
35
|
-
"uuid": "00000025-0000-1000-8000-0026BB765291",
|
|
36
|
-
"type": "On",
|
|
37
|
-
"serviceType": "Fan",
|
|
38
|
-
"serviceName": "Bunkie Fan",
|
|
39
|
-
"description": "On",
|
|
40
|
-
"value": 1,
|
|
41
|
-
"format": "bool",
|
|
42
|
-
"perms": [
|
|
43
|
-
"ev",
|
|
44
|
-
"pr",
|
|
45
|
-
"pw"
|
|
46
|
-
],
|
|
47
|
-
"canRead": true,
|
|
48
|
-
"canWrite": true,
|
|
49
|
-
"ev": true
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
"aid": 167,
|
|
53
|
-
"iid": 11,
|
|
54
|
-
"uuid": "000000E3-0000-1000-8000-0026BB765291",
|
|
55
|
-
"type": "ConfiguredName",
|
|
56
|
-
"serviceType": "Fan",
|
|
57
|
-
"serviceName": "Bunkie Fan",
|
|
58
|
-
"description": "Configured Name",
|
|
59
|
-
"value": "Bunkie Fan",
|
|
60
|
-
"format": "string",
|
|
61
|
-
"perms": [
|
|
62
|
-
"ev",
|
|
63
|
-
"pr",
|
|
64
|
-
"pw"
|
|
65
|
-
],
|
|
66
|
-
"canRead": true,
|
|
67
|
-
"canWrite": true,
|
|
68
|
-
"ev": true
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
"aid": 167,
|
|
72
|
-
"iid": 12,
|
|
73
|
-
"uuid": "00000029-0000-1000-8000-0026BB765291",
|
|
74
|
-
"type": "RotationSpeed",
|
|
75
|
-
"serviceType": "Fan",
|
|
76
|
-
"serviceName": "Bunkie Fan",
|
|
77
|
-
"description": "Rotation Speed",
|
|
78
|
-
"value": 33,
|
|
79
|
-
"format": "float",
|
|
80
|
-
"perms": [
|
|
81
|
-
"ev",
|
|
82
|
-
"pr",
|
|
83
|
-
"pw"
|
|
84
|
-
],
|
|
85
|
-
"unit": "percentage",
|
|
86
|
-
"maxValue": 100,
|
|
87
|
-
"minValue": 0,
|
|
88
|
-
"minStep": 1,
|
|
89
|
-
"canRead": true,
|
|
90
|
-
"canWrite": true,
|
|
91
|
-
"ev": true
|
|
92
|
-
}
|
|
93
|
-
],
|
|
94
|
-
"accessoryInformation": {
|
|
95
|
-
"Manufacturer": "Tasmota",
|
|
96
|
-
"Model": "Sonoff iFan03",
|
|
97
|
-
"Name": "Bunkie Fan",
|
|
98
|
-
"Serial Number": "302D6B-jessie",
|
|
99
|
-
"Firmware Revision": "9.5.0tasmota"
|
|
100
|
-
},
|
|
101
|
-
"values": {
|
|
102
|
-
"On": 1,
|
|
103
|
-
"ConfiguredName": "Bunkie Fan",
|
|
104
|
-
"RotationSpeed": 33
|
|
105
|
-
},
|
|
106
|
-
"instance": {
|
|
107
|
-
"name": "homebridge",
|
|
108
|
-
"username": "1C:22:3D:E3:CF:34",
|
|
109
|
-
"ipAddress": "192.168.1.11",
|
|
110
|
-
"port": 35215,
|
|
111
|
-
"services": [],
|
|
112
|
-
"connectionFailedCount": 0
|
|
113
|
-
},
|
|
114
|
-
"uniqueId": "9fd9e494282f14d80d438aad8ffde153893f99a97195b816749786e9a012aa2f"
|
|
115
|
-
},
|
|
116
|
-
// Add more inputs here if needed
|
|
117
|
-
];
|
|
118
|
-
|
|
119
|
-
const perms = { perms: 'ev' };
|
|
120
|
-
|
|
121
|
-
const result = hbConfigNode.toList(inputs, perms);
|
|
122
|
-
/*
|
|
123
|
-
{
|
|
124
|
-
"homebridge": "homebridge",
|
|
125
|
-
"host": "192.168.1.11",
|
|
126
|
-
"port": 35215,
|
|
127
|
-
"id": "1C:22:3D:E3:CF:34",
|
|
128
|
-
"manufacturer": "Tasmota",
|
|
129
|
-
"aid": 75,
|
|
130
|
-
"type": "00000043",
|
|
131
|
-
"name": "West Bedroom",
|
|
132
|
-
"service": "Lightbulb",
|
|
133
|
-
"fullName": "West Bedroom - Lightbulb",
|
|
134
|
-
"sortName": "West Bedroom:Lightbulb",
|
|
135
|
-
"uniqueId": "homebridge1C:22:3D:E3:CF:34TasmotaWest Bedroom00000043",
|
|
136
|
-
"descriptions": "On",
|
|
137
|
-
"characteristics": {
|
|
138
|
-
"75.10": {
|
|
139
|
-
"characteristic": "On",
|
|
140
|
-
"iid": 10
|
|
141
|
-
}
|
|
142
|
-
},
|
|
143
|
-
"getCharacteristics": "75.10",
|
|
144
|
-
"eventRegisters": [{
|
|
145
|
-
"aid": 75,
|
|
146
|
-
"iid": 10,
|
|
147
|
-
"ev": true
|
|
148
|
-
}]
|
|
149
|
-
}
|
|
150
|
-
*/
|
|
151
|
-
|
|
152
|
-
expect(result).toHaveLength(1);
|
|
153
|
-
console.log(result);
|
|
154
|
-
/*
|
|
155
|
-
expect(result).toEqual([
|
|
156
|
-
{
|
|
157
|
-
uniqueId: "1",
|
|
158
|
-
serviceName: "Service 1",
|
|
159
|
-
characteristics: [
|
|
160
|
-
{
|
|
161
|
-
id: "1.1",
|
|
162
|
-
type: "Type 1",
|
|
163
|
-
description: "Description 1",
|
|
164
|
-
value: "Value 1",
|
|
165
|
-
format: "Format 1",
|
|
166
|
-
unit: "Unit 1",
|
|
167
|
-
perms: ["perm1", "perm2"],
|
|
168
|
-
canRead: true,
|
|
169
|
-
canWrite: false,
|
|
170
|
-
ev: true
|
|
171
|
-
},
|
|
172
|
-
// Add more expected characteristics here if needed
|
|
173
|
-
]
|
|
174
|
-
},
|
|
175
|
-
// Add more expected outputs here if needed
|
|
176
|
-
]);
|
|
177
|
-
*/
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
afterAll(async () => {
|
|
181
|
-
// eslint-disable-next-line no-console
|
|
182
|
-
console.log('destroy');
|
|
183
|
-
// await hap.destroy();
|
|
184
|
-
});
|
|
185
|
-
});
|
package/src/lib/logger.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
export class Log {
|
|
2
|
-
|
|
3
|
-
constructor(logger, debugMode) {
|
|
4
|
-
this.logger = logger;
|
|
5
|
-
this.debugMode = debugMode;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
debug(msg) {
|
|
9
|
-
if (this.debugMode) {
|
|
10
|
-
this.logger.info(msg);
|
|
11
|
-
} else {
|
|
12
|
-
this.logger.debug(msg);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
info(msg) {
|
|
17
|
-
this.logger.info(msg);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
warn(msg) {
|
|
21
|
-
this.logger.warn(msg);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
error(msg) {
|
|
25
|
-
this.logger.error(msg);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
log(msg) {
|
|
29
|
-
this.logger.info(msg);
|
|
30
|
-
}
|
|
31
|
-
}
|