node-red-contrib-homebridge-automation 0.1.12-beta.21 → 0.1.12-beta.23

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.21",
3
+ "version": "0.1.12-beta.23",
4
4
  "description": "NodeRED Automation for HomeBridge",
5
5
  "main": "src/HAP-NodeRed.js",
6
6
  "scripts": {
@@ -48,7 +48,7 @@
48
48
  "dependencies": {
49
49
  "better-queue": ">=3.8.12",
50
50
  "debug": "^4.3.5",
51
- "@homebridge/hap-client": "2.0.4"
51
+ "@homebridge/hap-client": "2.0.5-beta.2"
52
52
  },
53
53
  "author": "NorthernMan54",
54
54
  "license": "ISC",
package/src/hbBaseNode.js CHANGED
@@ -24,8 +24,19 @@ class HbBaseNode {
24
24
  this.on('input', this.handleInput.bind(this));
25
25
  }
26
26
  this.on('close', this.handleClose.bind(this));
27
+ this.hbConfigNode.on('event', this.handleHBEventMessage.bind(this));
28
+ this.on('topic', this.handleHBTopicMessage.bind(this));
27
29
  }
28
30
 
31
+ handleHBEventMessage(service) {
32
+ debug('event for', this.id, service.serviceName, service.values);
33
+ }
34
+
35
+ handleHBTopicMessage(service) {
36
+ debug('topic for', this.id, service.serviceName, service.values);
37
+ }
38
+
39
+
29
40
  registerNode() {
30
41
  debug("Registering node:", this.fullName);
31
42
  this.hbDevice = hbDevices.findDevice(this.device);
@@ -38,6 +49,7 @@ class HbBaseNode {
38
49
  }
39
50
 
40
51
  handleClose(callback) {
52
+ debug('close', this.name);
41
53
  callback();
42
54
  }
43
55
 
@@ -101,29 +113,6 @@ class HbBaseNode {
101
113
  }
102
114
  }
103
115
 
104
- async _control(node, payload) {
105
- try {
106
- const device = hbDevices.findDevice(node.device, { perms: 'pw' });
107
- if (!device) throw new Error('Device not available');
108
-
109
- const message = typeof payload === "object"
110
- ? this._createControlMessage(payload, node, device)
111
- : null;
112
-
113
- if (message && message.characteristics.length > 0) {
114
- const status = await this.HAPcontrolByDeviceIDAsync(device.id, JSON.stringify(message));
115
- node.status({ text: 'Controlled', shape: 'dot', fill: 'green' });
116
- return status;
117
- } else {
118
- throw new Error('Invalid payload');
119
- }
120
- } catch (err) {
121
- debug("Error in _control:", err);
122
- node.status({ text: 'Control error', shape: 'ring', fill: 'red' });
123
- throw err;
124
- }
125
- }
126
-
127
116
  async _register(node) {
128
117
  try {
129
118
  const device = hbDevices.findDevice(node.device, { perms: 'ev' });
@@ -1,12 +1,13 @@
1
- const hbBaseNode = require('./hbBaseNode.js');
1
+ // const EventEmitter = require('events'); // Import EventEmitter
2
2
  const { HapClient } = require('@homebridge/hap-client');
3
3
  const debug = require('debug')('hapNodeRed:hbConfigNode');
4
- const { Homebridges } = require('./lib/Homebridges.js');
5
4
  const { Log } = require('./lib/logger.js');
6
5
  const Queue = require('better-queue');
7
6
 
8
- class HBConfigNode {
7
+ class HBConfigNode { // Extend EventEmitter
9
8
  constructor(config, RED) {
9
+ // super(); // Call EventEmitter's constructor
10
+
10
11
  if (!config.jest) {
11
12
  RED.nodes.createNode(this, config);
12
13
 
@@ -18,6 +19,7 @@ class HBConfigNode {
18
19
  this.ctDevices = [];
19
20
  this.hbDevices = [];
20
21
  this.clientNodes = [];
22
+ this.monitorNodes = [];
21
23
  this.log = new Log(console, true);
22
24
 
23
25
  this.reqisterQueue = new Queue(this._register.bind(this), {
@@ -40,6 +42,7 @@ class HBConfigNode {
40
42
  this.hapClient.on('instance-discovered', this.waitForNoMoreDiscoveries);
41
43
 
42
44
  this.on('close', () => {
45
+ debug('close');
43
46
  this.close();
44
47
  });
45
48
  }
@@ -122,15 +125,59 @@ class HBConfigNode {
122
125
  for (const clientNode of clientNodes) {
123
126
  debug('_Register %s -> %s', clientNode.type, clientNode.name);
124
127
  clientNode.hbDevice = this.hbDevices.find(service => {
125
- const testValue = `${service.instance.name}${service.instance.username}${service.accessoryInformation.Manufacturer}${service.serviceName}${service.uuid.slice(0, 8)}`;
128
+ const deviceUnique = `${service.instance.name}${service.instance.username}${service.accessoryInformation.Manufacturer}${service.serviceName}${service.uuid.slice(0, 8)}`;
126
129
  clientNode.status({ fill: 'green', shape: 'dot', text: 'connected' });
127
- return clientNode.device === testValue;
130
+ return clientNode.device === deviceUnique;
128
131
  });
129
132
 
133
+ debug(clientNode.type);
134
+ if (clientNode.config.type === 'hb-status') {
135
+ debug('Adding', clientNode.name, clientNode.device)
136
+ this.monitorNodes[clientNode.device] = clientNode.hbDevice;
137
+ }
138
+ console.log(this.monitorNodes);
130
139
  if (!clientNode.hbDevice) {
131
140
  console.error('ERROR: _register - HB Device Missing', clientNode.name);
132
141
  }
133
142
  }
143
+ debug(`Registering ${Object.keys(this.monitorNodes).length} nodes for events`);
144
+ // console.log(Object.keys(this.monitorNodes));
145
+ if (Object.keys(this.monitorNodes).length) {
146
+ debug(`Registering ${Object.keys(this.monitorNodes).length} nodes for events`);
147
+ this.monitor = await this.hapClient.monitorCharacteristics(Object.values(this.monitorNodes));
148
+ this.monitor.on('service-update', (services) => {
149
+ // Emit events for updated services
150
+ for (const service of services) {
151
+ debug(`${service.instance.name}${service.instance.username}${service.accessoryInformation.Manufacturer}${service.serviceName}${service.uuid.slice(0, 8)}`,
152
+ service.values)
153
+ this.emit(
154
+ `${service.instance.name}${service.instance.username}${service.accessoryInformation.Manufacturer}${service.serviceName}${service.uuid.slice(0, 8)}`,
155
+ service.values
156
+ );
157
+ debug('event',
158
+ service.serviceName, service.values)
159
+ this.emit(
160
+ 'event',
161
+ service
162
+ );
163
+ // console.log(this.clientNodes);
164
+
165
+ const eventNodes = Object.values(this.clientNodes).filter(
166
+
167
+ (clientNode) =>
168
+ clientNode.config.device === `${service.instance.name}${service.instance.username}${service.accessoryInformation.Manufacturer}${service.serviceName}${service.uuid.slice(0, 8)}`
169
+
170
+ );
171
+ console.log('eventNodes, ', eventNodes);
172
+ eventNodes.forEach((eventNode) => {
173
+ debug('emit', eventNode.name, eventNode.type)
174
+ if (eventNode._events && typeof eventNode.emit === 'function') {
175
+ eventNode.emit('topic', service);
176
+ }
177
+ });
178
+ }
179
+ });
180
+ }
134
181
  cb(null);
135
182
  }
136
183
 
@@ -145,7 +192,7 @@ class HBConfigNode {
145
192
 
146
193
  close() {
147
194
  if (this.hapClient) {
148
- this.hapClient.close();
195
+ this.hapClient.destroy();
149
196
  }
150
197
  }
151
198
  }
@@ -8,7 +8,6 @@ class HbControlNode extends hbBaseNode {
8
8
 
9
9
  async handleInput(message) {
10
10
  debug('handleInput', message.payload, this.name);
11
-
12
11
  if (!this.hbDevice) {
13
12
  this.error('HB not initialized');
14
13
  this.status({ text: 'HB not initialized', shape: 'ring', fill: 'red' });
@@ -20,7 +19,7 @@ class HbControlNode extends hbBaseNode {
20
19
  .filter(key => key !== 'ConfiguredName')
21
20
  .join(', ');
22
21
  this.error(`Payload should be a JSON object containing device characteristics and values, e.g. {"On":false, "Brightness":0}. Valid values: ${validNames}`);
23
- this.status({ text: 'Invalid payload', shape: 'ring', fill: 'red' });
22
+ this.status({ text: 'Invalid payload', shape: 'dot', fill: 'red' });
24
23
  return;
25
24
  }
26
25
 
@@ -28,19 +27,13 @@ class HbControlNode extends hbBaseNode {
28
27
  let fill = 'green';
29
28
 
30
29
  for (const key of Object.keys(message.payload)) {
31
- const characteristic = this.hbDevice.serviceCharacteristics.find(c => c.type === key);
32
-
33
- if (characteristic) {
34
- try {
35
- const result = await characteristic.setValue(message.payload[key]);
36
- results.push({ [result.type]: result.value });
37
- } catch (error) {
38
- this.error(`Failed to set value for ${key}: ${error.message}`);
39
- fill = 'red';
40
- }
41
- } else {
42
- this.error(`Invalid characteristic '${key}' found in the message: ${JSON.stringify(message.payload)}`);
43
- results.push({ 'Invalid Key': key });
30
+
31
+ try {
32
+ const result = await this.hbDevice.setCharacteristicByType(key, message.payload[key]);
33
+ results.push({ [result.type]: result.value });
34
+ } catch (error) {
35
+ this.error(`Failed to set value for ${key}: ${error.message}`);
36
+ results.push({ key: key + ' ' + error.message })
44
37
  fill = 'red';
45
38
  }
46
39
  }
@@ -51,10 +44,6 @@ class HbControlNode extends hbBaseNode {
51
44
  fill,
52
45
  });
53
46
  }
54
-
55
- handleClose(callback) {
56
- callback();
57
- }
58
47
  }
59
48
 
60
49
  module.exports = HbControlNode;
@@ -1,51 +1,29 @@
1
- const HbBaseNode = require('./hbBaseNode'); // Path to HbBaseNode file
1
+ const HbBaseNode = require('./hbBaseNode');
2
2
  const debug = require('debug')('hapNodeRed:hbStatusNode');
3
3
 
4
4
  class HbStatusNode extends HbBaseNode {
5
5
  constructor(config, RED) {
6
- // console.log('hbStatusNode - contructor', config);
7
6
  super(config, RED);
8
7
  }
9
8
 
10
- /**
11
- * Handle input events specific to HbStatusNode
12
- * @param {Object} msg - Input message
13
- */
14
- handleInput(msg, send, done) {
15
- this.msg = msg;
16
- debug('handleInput', this);
17
- this.node._status(this.device, this, { perms: 'pr' }, (err, message) => {
18
- if (!err) {
19
- debug(
20
- "hbStatus received: %s = %s",
21
- JSON.stringify(this.fullName),
22
- JSON.stringify(message).slice(0, 80) + '...',
23
- JSON.stringify(this.hbDevice)
24
- );
9
+ async handleInput(message) {
10
+ debug('handleInput', message.payload, this.name);
25
11
 
26
- this.msg.name = this.name;
27
- this.msg._rawMessage = message;
28
- this.msg.payload = this._convertHBcharactericToNode(message.characteristics, this);
12
+ if (!this.hbDevice) {
13
+ this.error('HB not initialized');
14
+ this.status({ text: 'HB not initialized', shape: 'ring', fill: 'red' });
15
+ return;
16
+ }
29
17
 
30
- if (this.hbDevice) {
31
- this.msg.Homebridge = this.hbDevice.homebridge;
32
- this.msg.Manufacturer = this.hbDevice.manufacturer;
33
- this.msg.Service = this.hbDevice.service;
34
- this.msg._device = this.device;
35
- this.msg._confId = this.confId;
36
- }
37
-
38
- this.status({
39
- text: JSON.stringify(this.msg.payload).slice(0, 30) + '...',
40
- shape: 'dot',
41
- fill: 'green',
42
- });
43
-
44
- this.send(this.msg);
45
- } else {
46
- this.error(err, this.msg);
47
- }
18
+ const result = await this.hbDevice.refreshCharacteristics();
19
+ this.status({
20
+ text: JSON.stringify(await this.hbDevice.values),
21
+ shape: 'dot',
22
+ fill: 'green'
48
23
  });
24
+
25
+ message.payload = result.values;
26
+ this.send(message);
49
27
  }
50
28
  }
51
29
 
@@ -81,7 +81,6 @@
81
81
  "id": "3d7babac3a298e60",
82
82
  "type": "hb-status",
83
83
  "z": "caef1e7b5b399e80",
84
- "d": true,
85
84
  "name": "West Bedroom",
86
85
  "Homebridge": "homebridge",
87
86
  "Manufacturer": "Tasmota",
@@ -108,7 +107,7 @@
108
107
  "device": "homebridge1C:22:3D:E3:CF:34TasmotaWest Bedroom00000043",
109
108
  "conf": "557aec8e8c47e61e",
110
109
  "x": 480,
111
- "y": 260,
110
+ "y": 300,
112
111
  "wires": [
113
112
  [
114
113
  "a866ae0bb24ce682"