node-red-contrib-homebridge-automation 0.1.12-beta.22 → 0.1.12-beta.24

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.22",
3
+ "version": "0.1.12-beta.24",
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,21 @@ class HbBaseNode {
24
24
  this.on('input', this.handleInput.bind(this));
25
25
  }
26
26
  this.on('close', this.handleClose.bind(this));
27
+ this.on('event', this.handleHBEventMessage.bind(this));
27
28
  }
28
29
 
30
+ handleHBEventMessage(service) {
31
+ debug('topic for', this.id, service.serviceName, service.values);
32
+
33
+ this.status({
34
+ text: JSON.stringify(service.values),
35
+ shape: 'dot',
36
+ fill: 'green',
37
+ });
38
+ this.send({ payload: service.values });
39
+ }
40
+
41
+
29
42
  registerNode() {
30
43
  debug("Registering node:", this.fullName);
31
44
  this.hbDevice = hbDevices.findDevice(this.device);
@@ -38,6 +51,7 @@ class HbBaseNode {
38
51
  }
39
52
 
40
53
  handleClose(callback) {
54
+ debug('close', this.name);
41
55
  callback();
42
56
  }
43
57
 
@@ -101,29 +115,6 @@ class HbBaseNode {
101
115
  }
102
116
  }
103
117
 
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
118
  async _register(node) {
128
119
  try {
129
120
  const device = hbDevices.findDevice(node.device, { perms: 'ev' });
@@ -1,7 +1,5 @@
1
- const hbBaseNode = require('./hbBaseNode.js');
2
1
  const { HapClient } = require('@homebridge/hap-client');
3
2
  const debug = require('debug')('hapNodeRed:hbConfigNode');
4
- const { Homebridges } = require('./lib/Homebridges.js');
5
3
  const { Log } = require('./lib/logger.js');
6
4
  const Queue = require('better-queue');
7
5
 
@@ -18,6 +16,7 @@ class HBConfigNode {
18
16
  this.ctDevices = [];
19
17
  this.hbDevices = [];
20
18
  this.clientNodes = [];
19
+ this.monitorNodes = [];
21
20
  this.log = new Log(console, true);
22
21
 
23
22
  this.reqisterQueue = new Queue(this._register.bind(this), {
@@ -39,9 +38,7 @@ class HBConfigNode {
39
38
  this.waitForNoMoreDiscoveries();
40
39
  this.hapClient.on('instance-discovered', this.waitForNoMoreDiscoveries);
41
40
 
42
- this.on('close', () => {
43
- this.close();
44
- });
41
+ this.on('close', this.close.bind(this));
45
42
  }
46
43
  }
47
44
 
@@ -67,19 +64,16 @@ class HBConfigNode {
67
64
  }
68
65
 
69
66
  toList(perms) {
70
- const supportedServiceType = (service) => {
71
- const supportedTypes = [
72
- 'Battery', 'Carbon Dioxide Sensor', 'Carbon Monoxide Sensor', 'Doorbell',
73
- 'Fan', 'Fanv2', 'Garage Door Opener', 'Humidity Sensor', 'Input Source',
74
- 'Leak Sensor', 'Lightbulb', 'Lock Mechanism', 'Motion Sensor', 'Occupancy Sensor',
75
- 'Outlet', 'Smoke Sensor', 'Speaker', 'Stateless Programmable Switch', 'Switch',
76
- 'Television', 'Temperature Sensor', 'Thermostat', 'Contact Sensor',
77
- ];
78
- return supportedTypes.includes(service.humanType);
79
- };
67
+ const supportedTypes = [
68
+ 'Battery', 'Carbon Dioxide Sensor', 'Carbon Monoxide Sensor', 'Doorbell',
69
+ 'Fan', 'Fanv2', 'Garage Door Opener', 'Humidity Sensor', 'Input Source',
70
+ 'Leak Sensor', 'Lightbulb', 'Lock Mechanism', 'Motion Sensor', 'Occupancy Sensor',
71
+ 'Outlet', 'Smoke Sensor', 'Speaker', 'Stateless Programmable Switch', 'Switch',
72
+ 'Television', 'Temperature Sensor', 'Thermostat', 'Contact Sensor',
73
+ ];
80
74
 
81
75
  return this.hbDevices
82
- .filter(service => supportedServiceType(service))
76
+ .filter(service => supportedTypes.includes(service.humanType))
83
77
  .map(service => ({
84
78
  name: service.serviceName,
85
79
  fullName: `${service.serviceName} - ${service.type}`,
@@ -122,30 +116,48 @@ class HBConfigNode {
122
116
  for (const clientNode of clientNodes) {
123
117
  debug('_Register %s -> %s', clientNode.type, clientNode.name);
124
118
  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)}`;
119
+ const deviceUnique = `${service.instance.name}${service.instance.username}${service.accessoryInformation.Manufacturer}${service.serviceName}${service.uuid.slice(0, 8)}`;
126
120
  clientNode.status({ fill: 'green', shape: 'dot', text: 'connected' });
127
- return clientNode.device === testValue;
121
+ return clientNode.device === deviceUnique;
128
122
  });
129
123
 
124
+ if (clientNode.config.type === 'hb-status') {
125
+ this.monitorNodes[clientNode.device] = clientNode.hbDevice;
126
+ }
127
+
130
128
  if (!clientNode.hbDevice) {
131
129
  console.error('ERROR: _register - HB Device Missing', clientNode.name);
132
130
  }
133
131
  }
132
+
133
+ if (Object.keys(this.monitorNodes).length) {
134
+ this.monitor = await this.hapClient.monitorCharacteristics(Object.values(this.monitorNodes));
135
+ this.monitor.on('service-update', (services) => {
136
+ for (const service of services) {
137
+ const eventNodes = Object.values(this.clientNodes).filter(
138
+ clientNode =>
139
+ clientNode.config.device === `${service.instance.name}${service.instance.username}${service.accessoryInformation.Manufacturer}${service.serviceName}${service.uuid.slice(0, 8)}`
140
+ );
141
+
142
+ eventNodes.forEach((eventNode) => {
143
+ if (eventNode._events && typeof eventNode.emit === 'function') {
144
+ eventNode.emit('event', service);
145
+ }
146
+ });
147
+ }
148
+ });
149
+ }
134
150
  cb(null);
135
151
  }
136
152
 
137
153
  deregister(clientNode) {
138
- clientNode.status({
139
- text: 'disconnected',
140
- shape: 'ring',
141
- fill: 'red',
142
- });
154
+ clientNode.status({ text: 'disconnected', shape: 'ring', fill: 'red' });
143
155
  delete this.clientNodes[clientNode.id];
144
156
  }
145
157
 
146
158
  close() {
147
159
  if (this.hapClient) {
148
- this.hapClient.close();
160
+ this.hapClient.destroy();
149
161
  }
150
162
  }
151
163
  }
@@ -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' });
@@ -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, send) {
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
+ 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"