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

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.24",
3
+ "version": "0.1.12-beta.25",
4
4
  "description": "NodeRED Automation for HomeBridge",
5
5
  "main": "src/HAP-NodeRed.js",
6
6
  "scripts": {
@@ -11,10 +11,7 @@ const HbStatusNode = require('./hbStatusNode');
11
11
  const HapDeviceRoutes = require('./HapDeviceRoutes');
12
12
 
13
13
  module.exports = function (RED) {
14
- var evDevices = [];
15
- var ctDevices = [];
16
14
  var hbDevices;
17
- var homebridge;
18
15
 
19
16
  /**
20
17
  * hbConf - Configuration
package/src/hbBaseNode.js CHANGED
@@ -24,11 +24,11 @@ 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
+ this.on('hbEvent', this.handleHBEventMessage.bind(this));
28
28
  }
29
29
 
30
30
  handleHBEventMessage(service) {
31
- debug('topic for', this.id, service.serviceName, service.values);
31
+ debug('hbEvent for', this.id, service.serviceName, service.values);
32
32
 
33
33
  this.status({
34
34
  text: JSON.stringify(service.values),
@@ -38,6 +38,18 @@ class HbBaseNode {
38
38
  this.send({ payload: service.values });
39
39
  }
40
40
 
41
+ createMessage(event, isInitialState = false) {
42
+ return {
43
+ name: this.node.name,
44
+ payload: this.state,
45
+ Homebridge: this.node.hbDevice.homebridge,
46
+ Manufacturer: this.node.hbDevice.manufacturer,
47
+ Service: this.node.hbDevice.deviceType,
48
+ _device: this.node.device,
49
+ _confId: this.node.confId,
50
+ _rawEvent: isInitialState ? event : undefined,
51
+ };
52
+ }
41
53
 
42
54
  registerNode() {
43
55
  debug("Registering node:", this.fullName);
@@ -117,7 +117,10 @@ class HBConfigNode {
117
117
  debug('_Register %s -> %s', clientNode.type, clientNode.name);
118
118
  clientNode.hbDevice = this.hbDevices.find(service => {
119
119
  const deviceUnique = `${service.instance.name}${service.instance.username}${service.accessoryInformation.Manufacturer}${service.serviceName}${service.uuid.slice(0, 8)}`;
120
- clientNode.status({ fill: 'green', shape: 'dot', text: 'connected' });
120
+ if (clientNode.device === deviceUnique) {
121
+ clientNode.status({ fill: 'green', shape: 'dot', text: 'connected' });
122
+ clientNode.emit('hbReady', service);
123
+ }
121
124
  return clientNode.device === deviceUnique;
122
125
  });
123
126
 
@@ -141,7 +144,7 @@ class HBConfigNode {
141
144
 
142
145
  eventNodes.forEach((eventNode) => {
143
146
  if (eventNode._events && typeof eventNode.emit === 'function') {
144
- eventNode.emit('event', service);
147
+ eventNode.emit('hbEvent', service);
145
148
  }
146
149
  });
147
150
  }
@@ -3,87 +3,21 @@ const debug = require('debug')('hapNodeRed:hbEventNode');
3
3
 
4
4
  class HbEventNode extends hbBaseNode {
5
5
  constructor(config, RED) {
6
- // console.log('HbEventNode', config);
7
6
  super(config, RED);
8
7
  this.sendInitialState = config.sendInitialState === true;
9
- this.hbConfigNode.register(this.config, this.registerNode.bind(this));
8
+ this.on('hbReady', this.handleHbReady.bind(this))
10
9
  }
11
10
 
12
- // Handle event command processing
13
- command(event) {
14
- if (event.status === true && event.value !== undefined) {
15
- this.state = { ...this.state, ...this._convertHBcharacteristicToNode([event]) };
16
- const msg = this.createMessage(event);
17
- this.updateStatus({ text: `${JSON.stringify(msg.payload).slice(0, 30)}...`, shape: 'dot', fill: 'green' });
18
- this.send(msg);
19
- } else if (event.status === true) {
20
- this.updateStatus({ text: 'connected', shape: 'dot', fill: 'green' });
21
- } else {
22
- this.updateStatus({ text: `disconnected: ${event.status}`, shape: 'ring', fill: 'red' });
23
- }
24
- }
25
-
26
- // Handle device registration logic
27
- handleDeviceRegistration() {
28
- debug('hbEvent.register', this);
29
- this.node.hbDevice = this.findDevice(this.node.device, { perms: 'pr' });
30
-
31
- if (this.node.hbDevice) {
32
- this.registerEventHandlers();
33
- this.fetchInitialState();
34
- } else {
35
- this.node.error(`Can't find device ${this.node.device}`);
36
- }
37
- }
38
-
39
- // Register for device events
40
- registerEventHandlers() {
41
- this.node.deviceType = this.node.hbDevice.deviceType;
42
- this.node.listener = this.command;
43
- this.node.eventName = [];
44
-
45
- this.node.hbDevice.eventRegisters.forEach((event) => {
46
- this.registerEvent(this.node.hbDevice.id + event.aid + event.iid);
47
- });
48
-
49
- this.updateStatus({ text: 'connected', shape: 'dot', fill: 'green' });
50
- }
51
-
52
- // Fetch and send initial state if required
53
- fetchInitialState() {
54
- this.fetchStatus(this.node.device, { perms: 'ev' }, (err, message) => {
55
- if (!err) {
56
- this.state = this._convertHBcharacteristicToNode(message.characteristics);
57
- debug(
58
- 'hbEvent received: %s = %s',
59
- this.node.fullName,
60
- `${JSON.stringify(message.characteristics).slice(0, 80)}...`
61
- );
62
-
63
- if (this.sendInitialState) {
64
- const msg = this.createMessage(message, true);
65
- this.updateStatus({ text: `${JSON.stringify(msg.payload).slice(0, 30)}...`, shape: 'dot', fill: 'green' });
66
- this.send(msg);
67
- }
68
- } else {
69
- this.node.error('hbEvent _status: error', this.node.fullName, err);
70
- }
11
+ handleHbReady(service) {
12
+ this.status({
13
+ text: JSON.stringify(service.values),
14
+ shape: 'dot',
15
+ fill: 'green',
71
16
  });
17
+ this.send({ payload: service.values });
72
18
  }
73
-
74
19
  // Create a message payload for event or initial state
75
- createMessage(event, isInitialState = false) {
76
- return {
77
- name: this.node.name,
78
- payload: this.state,
79
- Homebridge: this.node.hbDevice.homebridge,
80
- Manufacturer: this.node.hbDevice.manufacturer,
81
- Service: this.node.hbDevice.deviceType,
82
- _device: this.node.device,
83
- _confId: this.node.confId,
84
- _rawEvent: isInitialState ? event : undefined,
85
- };
86
- }
20
+
87
21
  }
88
22
 
89
23
  module.exports = HbEventNode;
@@ -19,10 +19,21 @@ class HbResumeNode extends HbBaseNode {
19
19
  // Handle device registration
20
20
  debug('hbResume - hbConfigNode', this.hbConfigNode);
21
21
  // debug('hbResume - hbConfigNode', this.configNode.hbConfigNode);
22
- this.hbConfigNode.register(this.config, this.registerNode.bind(this));
22
+
23
+ }
24
+
25
+ handleHBEventMessage(service) {
26
+ debug('topic for', this.id, service.serviceName, service.values);
27
+
28
+ this.status({
29
+ text: JSON.stringify(service.values),
30
+ shape: 'dot',
31
+ fill: 'green',
32
+ });
33
+ this.send({ payload: service.values });
23
34
  }
24
35
 
25
- handleInput(msg) {
36
+ handleInput(msg, send) {
26
37
  this.msg = msg;
27
38
  debug("hbResume.input: %s input", this.fullName, JSON.stringify(msg));
28
39
 
@@ -51,7 +62,7 @@ class HbResumeNode extends HbBaseNode {
51
62
  newMsg = msg;
52
63
  }
53
64
 
54
- this.send(newMsg.payload.On ? newMsg : { ...newMsg, payload: { On: false } });
65
+ send(newMsg.payload.On ? newMsg : { ...newMsg, payload: { On: false } });
55
66
  debug("hbResume.input: %s output", this.fullName, JSON.stringify(newMsg));
56
67
  this.updateStatus(newMsg.payload);
57
68
  this.lastMessageValue = newMsg.payload;
@@ -95,48 +95,10 @@
95
95
  ]
96
96
  ]
97
97
  },
98
- {
99
- "id": "696e04753d952daf",
100
- "type": "hb-status",
101
- "z": "caef1e7b5b399e80",
102
- "d": true,
103
- "name": "West Bedroom",
104
- "Homebridge": "homebridge",
105
- "Manufacturer": "Tasmota",
106
- "Service": "Lightbulb",
107
- "device": "homebridge1C:22:3D:E3:CF:34TasmotaWest Bedroom00000043",
108
- "conf": "557aec8e8c47e61e",
109
- "x": 480,
110
- "y": 300,
111
- "wires": [
112
- [
113
- "a866ae0bb24ce682"
114
- ]
115
- ]
116
- },
117
- {
118
- "id": "bb88544904b343a1",
119
- "type": "hb-event",
120
- "z": "caef1e7b5b399e80",
121
- "d": true,
122
- "name": "",
123
- "Homebridge": "homebridge",
124
- "Manufacturer": "Tasmota",
125
- "Service": "Lightbulb",
126
- "device": "homebridge1C:22:3D:E3:CF:34TasmotaWest Bedroom00000043",
127
- "conf": "557aec8e8c47e61e",
128
- "sendInitialState": false,
129
- "x": 250,
130
- "y": 380,
131
- "wires": [
132
- []
133
- ]
134
- },
135
98
  {
136
99
  "id": "452e3e6171aa7a25",
137
100
  "type": "hb-resume",
138
101
  "z": "caef1e7b5b399e80",
139
- "d": true,
140
102
  "name": "West Bedroom",
141
103
  "Homebridge": "homebridge",
142
104
  "Manufacturer": "Tasmota",
@@ -179,7 +141,7 @@
179
141
  "device": "homebridge1C:22:3D:E3:CF:34TasmotaWest Bedroom Fan00000040",
180
142
  "conf": "557aec8e8c47e61e",
181
143
  "outputs": 0,
182
- "x": 510,
144
+ "x": 810,
183
145
  "y": 600,
184
146
  "wires": []
185
147
  },
@@ -223,8 +185,8 @@
223
185
  "device": "homebridge1C:22:3D:E3:CF:34TasmotaWest Bedroom00000043",
224
186
  "conf": "557aec8e8c47e61e",
225
187
  "outputs": 0,
226
- "x": 740,
227
- "y": 660,
188
+ "x": 800,
189
+ "y": 680,
228
190
  "wires": []
229
191
  },
230
192
  {
@@ -401,5 +363,82 @@
401
363
  "6703815a8874b156"
402
364
  ]
403
365
  ]
366
+ },
367
+ {
368
+ "id": "80ffdbb93cd24b48",
369
+ "type": "inject",
370
+ "z": "caef1e7b5b399e80",
371
+ "name": "",
372
+ "props": [
373
+ {
374
+ "p": "payload"
375
+ },
376
+ {
377
+ "p": "topic",
378
+ "vt": "str"
379
+ }
380
+ ],
381
+ "repeat": "",
382
+ "crontab": "",
383
+ "once": false,
384
+ "onceDelay": 0.1,
385
+ "topic": "",
386
+ "payload": "{\"On\": true}",
387
+ "payloadType": "json",
388
+ "x": 150,
389
+ "y": 340,
390
+ "wires": [
391
+ [
392
+ "452e3e6171aa7a25"
393
+ ]
394
+ ]
395
+ },
396
+ {
397
+ "id": "d0e413b3c28f757a",
398
+ "type": "inject",
399
+ "z": "caef1e7b5b399e80",
400
+ "name": "",
401
+ "props": [
402
+ {
403
+ "p": "payload"
404
+ },
405
+ {
406
+ "p": "topic",
407
+ "vt": "str"
408
+ }
409
+ ],
410
+ "repeat": "",
411
+ "crontab": "",
412
+ "once": false,
413
+ "onceDelay": 0.1,
414
+ "topic": "",
415
+ "payload": "{\"On\": false}",
416
+ "payloadType": "json",
417
+ "x": 150,
418
+ "y": 400,
419
+ "wires": [
420
+ [
421
+ "452e3e6171aa7a25"
422
+ ]
423
+ ]
424
+ },
425
+ {
426
+ "id": "82638dac6ac32bb1",
427
+ "type": "hb-event",
428
+ "z": "caef1e7b5b399e80",
429
+ "name": "West Bedroom",
430
+ "Homebridge": "homebridge",
431
+ "Manufacturer": "Tasmota",
432
+ "Service": "Lightbulb",
433
+ "device": "homebridge1C:22:3D:E3:CF:34TasmotaWest Bedroom00000043",
434
+ "conf": "557aec8e8c47e61e",
435
+ "sendInitialState": true,
436
+ "x": 500,
437
+ "y": 260,
438
+ "wires": [
439
+ [
440
+ "a866ae0bb24ce682"
441
+ ]
442
+ ]
404
443
  }
405
444
  ]
package/src/hbDevices.js DELETED
@@ -1,10 +0,0 @@
1
- const { Homebridges } = require('./lib/Homebridges.js');
2
- const HAPNodeJSClient = require('hap-node-client').HAPNodeJSClient;
3
-
4
- class hbDevices {
5
-
6
-
7
-
8
- }
9
-
10
- modules.export = hbDevices;
@@ -1,126 +0,0 @@
1
- var debug = require('debug')('Accessory');
2
- var Service = require('./Service.js').Service;
3
-
4
- module.exports = {
5
- Accessory: Accessory
6
- };
7
-
8
- /*
9
- * Homebridges -> Homebridge -> Accessory -> Service -> Characteristic
10
- */
11
-
12
- function Accessory(devices, context) {
13
- // debug("Accessory", devices);
14
- this.aid = devices.aid;
15
- this.host = context.host;
16
- this.port = context.port;
17
- this.homebridge = context.homebridge;
18
- this.id = context.id;
19
- this.services = [];
20
- devices.services.forEach(function (element) {
21
- // debug("Service", element);
22
- switch (element.type.substring(0, 8)) {
23
- case "0000003E": // Accessory Information
24
- this.info = information(element.characteristics);
25
- break;
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;
35
- case "000000D9": // Input Source from webosTV has a dummy input source
36
- var service = new Service(element, this);
37
- if (service.name !== "dummy") {
38
- this.services.push(service);
39
- }
40
- break;
41
- default:
42
- var service = new Service(element, this);
43
- this.services.push(service);
44
- }
45
- }.bind(this));
46
- // debug("Info", this.info);
47
- }
48
-
49
- Accessory.prototype.toList = function (context) {
50
- var list = [];
51
- // debug("toList", context);
52
- context.aid = this.aid;
53
- if (!this.info) {
54
- console.log("ERROR: incorrect version of plugin, please upgrade");
55
- }
56
- context.name = this.info.Name;
57
- context.manufacturer = this.info.Manufacturer;
58
- for (var index in this.services) {
59
- var service = this.services[index].toList(context);
60
- if (service) {
61
- list = list.concat(service);
62
- }
63
- }
64
-
65
- // debug('toList', new Error('test'));
66
- // debug("opt",context.opt,list.length);
67
- return (list);
68
- };
69
-
70
- /*
71
- [ { iid: 2,
72
- type: '00000014-0000-1000-8000-0026BB765291',
73
- perms: [Array],
74
- format: 'bool',
75
- description: 'Identify' },
76
- { iid: 3,
77
- type: '00000020-0000-1000-8000-0026BB765291',
78
- perms: [Array],
79
- format: 'string',
80
- value: 'NorthernMan54',
81
- description: 'Manufacturer' },
82
- { iid: 4,
83
- type: '00000021-0000-1000-8000-0026BB765291',
84
- perms: [Array],
85
- format: 'string',
86
- value: 'dht22',
87
- description: 'Model' },
88
- { iid: 5,
89
- type: '00000023-0000-1000-8000-0026BB765291',
90
- perms: [Array],
91
- format: 'string',
92
- value: 'Basement',
93
- description: 'Name' },
94
- { iid: 6,
95
- type: '00000030-0000-1000-8000-0026BB765291',
96
- perms: [Array],
97
- format: 'string',
98
- value: 'penny-Basement',
99
- description: 'Serial Number' },
100
- { iid: 7,
101
- type: '00000052-0000-1000-8000-0026BB765291',
102
- perms: [Array],
103
- format: 'string',
104
- value: '0.1.21',
105
- description: 'Firmware Revision' } ],
106
- */
107
-
108
- /*
109
- { Identify: undefined,
110
- Manufacturer: 'Default-Manufacturer',
111
- Model: 'Default-Model',
112
- Name: 'FHall',
113
- SerialNumber: 'Default-SerialNumber',
114
- FirmwareRevision: '1.0' }
115
- */
116
-
117
- function information(characteristics) {
118
- var result = {};
119
- characteristics.forEach(function (characteristic) {
120
- if (characteristic.description) {
121
- var key = characteristic.description.replace(/ /g, '').replace(/\./g, '_');
122
- result[key] = characteristic.value;
123
- }
124
- });
125
- return result;
126
- }
@@ -1,30 +0,0 @@
1
- var debug = require('debug')('Characteristic');
2
- // var Service = require('./Service.js').Service;
3
-
4
- module.exports = {
5
- Characteristic: Characteristic
6
- };
7
-
8
- /*
9
- * Homebridges -> Homebridge -> Accessory -> Service -> Characteristic
10
- */
11
-
12
- function Characteristic(devices, context) {
13
- // debug("Characteristic", devices);
14
- this.iid = devices.iid;
15
- this.type = devices.type.substring(0, 8);
16
- this.perms = devices.perms;
17
- this.value = devices.value;
18
- this.description = (devices.description ? devices.description : this.type);
19
- this.characteristic = {};
20
- this.getCharacteristic = context.aid + '.' + this.iid;
21
- this.characteristic[this.getCharacteristic] = {
22
- characteristic: this.description.replace(/ /g, "").replace(/\./g, "_"),
23
- iid: this.iid
24
- };
25
- this.eventRegister = {
26
- aid: context.aid,
27
- iid: this.iid,
28
- "ev": true
29
- };
30
- }
@@ -1,167 +0,0 @@
1
- var debug = require('debug')('HbAccessories');
2
-
3
- module.exports = {
4
- HbAccessories: HbAccessories
5
- };
6
-
7
- function HbAccessories(devices, opt) {
8
- debug("HbAccessories", devices);
9
- if (typeof devices === 'array') {
10
- devices.forEach(function(element) {
11
- // debug('Device', element);
12
- events = events.concat(_instance(element, perms));
13
- });
14
- }
15
- }
16
-
17
- /*
18
- function registerEv(homebridge, devices) {
19
- return register(homebridge, devices, 'ev');
20
- }
21
-
22
- function registerCt(homebridge, devices) {
23
- return register(homebridge, devices, 'pw');
24
- }
25
- */
26
-
27
- function register(homebridge, devices, perms) {
28
- // debug('Discovered', devices);
29
- var events = [];
30
- devices.forEach(function(element) {
31
- // debug('Device', element);
32
- events = events.concat(_instance(element, perms));
33
- });
34
- return (events);
35
- }
36
-
37
- function _instance(instance, perms) {
38
- // debug('Accessories', instance.accessories.accessories);
39
- var events = [];
40
- instance.accessories.accessories.forEach(function(accessory) {
41
- // debug('Accessory', instance.instance.txt);
42
- events = events.concat(_service({
43
- "host": instance.ipAddress,
44
- "port": instance.instance.port,
45
- "homebridge": instance.instance.txt.md,
46
- "id": instance.instance.txt.id,
47
- "aid": accessory.aid
48
- }, accessory.services, perms));
49
- });
50
- return (events);
51
- }
52
-
53
- function _service(context, accessory, perms) {
54
- var events = [];
55
- accessory.forEach(function(service) {
56
- // debug('Service', service);
57
- switch (service.type.substring(0, 8)) {
58
- case "00000043": // Lightbulb
59
- case "00000047": // Outlet
60
- case "00000049": // Switch
61
- case "00000040": // Fan
62
- case "0000008C": // WindowCovering
63
- case "0000008A": // TemperatureSensor
64
- case "000000B7": // Fan 2 aka Dyson
65
- case "00000041": // Garage Door
66
- case "000000D0": // Valve aka sprinkler
67
- // case "0000003E": // AccessoryInformation
68
- case "0000004A": // Thermostat
69
- case "00000080": // Contact Sensor
70
- case "00000085": // Motion Sensor
71
- case "00000111": // Camera
72
- // debug('Supported Service', service);
73
- events = events.concat(_characteristics(context, service, perms));
74
- // debug("Events", events);
75
- break;
76
- case "0000003E": // AccessoryInformation
77
- _name(context, service);
78
- // debug("Events", events);
79
- break;
80
- default:
81
- }
82
- });
83
- return (events);
84
- }
85
-
86
- function _characteristics(context, service, perms) {
87
- // debug("Char", service, Array.isArray(service));
88
-
89
- var events = [];
90
- service.characteristics.forEach(function(characteristic) {
91
- switch (characteristic.type.substring(0, 8)) {
92
- case "00000020": // manufacturer
93
- context.manufacturer = characteristic.value;
94
- break;
95
- case "00000023": // name
96
- context.name = characteristic.value;
97
- break;
98
- }
99
-
100
- if (characteristic.perms.includes(perms)) {
101
- context.iid = characteristic.iid;
102
- context.function = characteristic.description;
103
- context.service = service.type.substring(0, 8);
104
- context.characteristic = characteristic.type.substring(0, 8);
105
- context.deviceType = _normalizeName(context.service);
106
- // debug("Register", context);
107
- context.fullName = context.name + ' - ' + _normalizeName(context.service) + ' - ' + context.function;
108
- context.sortName = context.name + ':' + _normalizeName(context.service) + ':' + context.function;
109
- context.uniqueId = context.homebridge + context.id + context.manufacturer + context.name + context.service + context.characteristic;
110
- // debug("Perms ", context.fullName, characteristic.perms);
111
- events.push(JSON.parse(JSON.stringify(context)));
112
- }
113
- });
114
- // debug("Char Events", events);
115
- return (events);
116
- }
117
-
118
- function _name(context, service) {
119
- // debug("Char", service, Array.isArray(service));
120
-
121
- var manufacturer, name;
122
- service.characteristics.forEach(function(characteristic) {
123
- switch (characteristic.type.substring(0, 8)) {
124
- case "00000020": // manufacturer
125
- context.manufacturer = characteristic.value;
126
- break;
127
- case "00000023": // name
128
- context.name = characteristic.value;
129
- break;
130
- }
131
- });
132
- // debug("Char Events", events);
133
- // return ({ "manufacturer": manufacturer, "name": name});
134
- }
135
-
136
- function _normalizeName(id) {
137
- switch (id) {
138
- case "00000043": // Lightbulb
139
- return ("Lightbulb");
140
- case "00000047": // Outlet
141
- return ("Outlet");
142
- case "00000049": // Switch
143
- return ("Switch");
144
- case "000000B7": // Fan 2 aka Dyson
145
- case "00000040": // Fan
146
- return ("Fan");
147
- case "0000008C": // WindowCovering
148
- return ("Blinds");
149
- case "0000008A": // TemperatureSensor
150
- return ("Temperature");
151
- case "00000041": // Garage Door
152
- return ("Garage Door");
153
- case "000000D0": // Valve aka sprinkler
154
- return ("Sprinkler");
155
- // case "0000003E": // AccessoryInformation
156
- case "0000004A": // Thermostat
157
- return ("Thermostat");
158
- case "00000080": // Contact Sensor
159
- return ("Contact");
160
- case "00000085": // Motion Sensor
161
- return ("Motion");
162
- case "00000111": // Camera
163
- return ("Camera");
164
- default:
165
- debug("Missing HB Type", id);
166
- }
167
- }
@@ -1,71 +0,0 @@
1
- var debug = require('debug')('Homebridge');
2
- var Accessory = require('./Accessory.js').Accessory;
3
-
4
- module.exports = {
5
- Homebridge: Homebridge
6
- };
7
-
8
- /*
9
- * Homebridges -> Homebridge -> Accessory -> Service -> Characteristic
10
- */
11
-
12
- /*
13
-
14
- { ipAddress: '192.168.1.202',
15
- instance:
16
- { addresses: [ '192.168.1.202', 'fe80::eab6:f43b:eb39:9d7f' ],
17
- name: 'Leonard-Aztest-A6F3',
18
- fqdn: 'Leonard-Aztest-A6F3._hap._tcp.local',
19
- host: 'AC_22_3D_E3_CE_32.local',
20
- referer:
21
- { address: '192.168.1.202',
22
- family: 'IPv4',
23
- port: 5353,
24
- size: 374 },
25
- port: 51828,
26
- type: 'hap',
27
- protocol: 'tcp',
28
- subtypes: [],
29
- rawTxt: <Buffer 11 6d 64 3d 4c 65 6f 6e 61 72 64 2d 41 7a 74 65 73 74 06 70 76 3d 31 2e 30 14 69 64 3d 41 43 3a 32 32 3a 33 44 3a 45 33 3a 43 45 3a 33 32 04 63 23 3d ... >,
30
- txt:
31
- { md: 'Leonard-Aztest',
32
- pv: '1.0',
33
- id: 'AC:22:3D:E3:CE:32',
34
- 'c#': '5',
35
- 's#': '1',
36
- ff: '0',
37
- ci: '2',
38
- sf: '1',
39
- sh: 'HjMYzQ==' } },
40
- accessories: { accessories: [ [Object], [Object] ] } }
41
- */
42
-
43
- function Homebridge(devices) {
44
- // debug("Homebridge", devices);
45
- this.accessories = [];
46
- this.host = devices.ipAddress;
47
- this.port = devices.instance.port;
48
- this.homebridge = devices.instance.txt.md;
49
- this.id = devices.instance.txt.id;
50
- devices.accessories.accessories.forEach(function(element) {
51
- var accessory = new Accessory(element, this);
52
- this.accessories.push(accessory);
53
- }.bind(this));
54
- }
55
-
56
- Homebridge.prototype.toList = function(opt) {
57
- var list = [];
58
- for (var index in this.accessories) {
59
- var accessory = this.accessories[index];
60
- list = list.concat(accessory.toList({
61
- host: this.host,
62
- port: this.port,
63
- homebridge: this.homebridge,
64
- id: this.id,
65
- opt: opt
66
- }));
67
- // list.push(accessory.toList());
68
- }
69
- // debug("opt",opt,list.length);
70
- return (list);
71
- };
@@ -1,68 +0,0 @@
1
- // var debug = require('debug')('Homebridges');
2
- var Homebridge = require('./Homebridge.js').Homebridge;
3
-
4
- module.exports = {
5
- Homebridges: Homebridges
6
- };
7
-
8
- /*
9
- * Homebridges -> Homebridge -> Accessory -> Service -> Characteristic
10
- */
11
-
12
- function Homebridges(devices) {
13
- // debug("Homebridges", devices);
14
- this.homebridges = [];
15
- devices.forEach(function(element) {
16
- var homebridge = new Homebridge(element);
17
- this.homebridges.push(homebridge);
18
- }.bind(this));
19
- }
20
-
21
- /**
22
- * Homebridges.toList - description
23
- *
24
- * @param {type} opt description
25
- * @return {type} description
26
- */
27
-
28
- Homebridges.prototype.toList = function(opt) {
29
- var list = [];
30
- for (var index in this.homebridges) {
31
- var homebridge = this.homebridges[index];
32
- // list.push(homebridge.toList());
33
- list = list.concat(homebridge.toList(opt));
34
- }
35
-
36
- list.sort((a, b) => (a.sortName > b.sortName) ? 1 : ((b.sortName > a.sortName) ? -1 : 0));
37
- // debug("opt",opt,list.length);
38
- return (list);
39
- };
40
-
41
- /* {
42
- "characteristics": [{
43
- "aid": endpoint.aid,
44
- "iid": endpoint.iid,
45
- "ev": true
46
- }]
47
- };
48
- */
49
-
50
- Homebridges.prototype.findDevice = function(node, opt) {
51
- var list = [];
52
- for (var index in this.homebridges) {
53
- var homebridge = this.homebridges[index];
54
- // list.push(homebridge.toList());
55
- list = list.concat(homebridge.toList(opt));
56
- }
57
- return (list.find(x => x.uniqueId === node));
58
- };
59
-
60
- Homebridges.prototype.findDeviceByName = function(name, opt) {
61
- var list = [];
62
- for (var index in this.homebridges) {
63
- var homebridge = this.homebridges[index];
64
- // list.push(homebridge.toList());
65
- list = list.concat(homebridge.toList(opt));
66
- }
67
- return (list.find(x => x.name === name));
68
- };
@@ -1,307 +0,0 @@
1
- var debug = require('debug')('Service');
2
- var Characteristic = require('./Characteristic.js').Characteristic;
3
-
4
- module.exports = {
5
- Service: Service
6
- };
7
-
8
- /*
9
- * Homebridges -> Homebridge -> Accessory -> Service -> Characteristic
10
- */
11
-
12
- /*
13
-
14
- This is a typical Service
15
-
16
- {
17
- "iid": 8,
18
- "type": "0000008A-0000-1000-8000-0026BB765291",
19
- "characteristics": [{
20
- "iid": 9,
21
- "type": "00000023-0000-1000-8000-0026BB765291",
22
- "perms": ["pr"],
23
- "format": "string",
24
- "value": "Cold Cellar",
25
- "description": "Name"
26
- }, {
27
- "iid": 10,
28
- "type": "00000011-0000-1000-8000-0026BB765291",
29
- "perms": ["pr", "ev"],
30
- "format": "float",
31
- "value": 4.9,
32
- "description": "Current Temperature",
33
- "unit": "celsius",
34
- "maxValue": 100,
35
- "minValue": -100,
36
- "minStep": 0.1
37
- }, {
38
- "iid": 11,
39
- "type": "00000010-0000-1000-8000-0026BB765291",
40
- "perms": ["pr", "ev"],
41
- "format": "float",
42
- "value": 51,
43
- "description": "Current Relative Humidity",
44
- "unit": "percentage",
45
- "maxValue": 100,
46
- "minValue": 0,
47
- "minStep": 1
48
- }, {
49
- "iid": 12,
50
- "type": "E863F10F-079E-48FF-8F27-9C2605A29F52",
51
- "perms": ["pr", "ev"],
52
- "format": "uint8",
53
- "value": 1011,
54
- "description": "Air Pressure",
55
- "unit": "mbar",
56
- "maxValue": 1200,
57
- "minValue": 800,
58
- "minStep": 1
59
- }],
60
- "primary": false,
61
- "hidden": false
62
- }
63
- */
64
-
65
- function Service(devices, context) {
66
- // debug("Service", JSON.stringify(devices));
67
- this.iid = devices.iid;
68
- this.type = devices.type.substring(0, 8);
69
- this.service = _normalizeName(this.type);
70
- this.aid = context.aid;
71
- this.host = context.host;
72
- this.port = context.port;
73
- this.homebridge = context.homebridge;
74
- this.id = context.id;
75
- this.characteristics = [];
76
- // Fix for homebridge 1.3.0
77
- devices.characteristics.forEach(function (element) {
78
- // var service = new Characteristic(element, this);
79
- if (element.type.substring(0, 8) === '00000023' && element.description === "Name") {
80
- this.name = element.value;
81
- } else if (element.type.substring(0, 8) === '000000E3' && element.description === "Configured Name") {
82
- this.configuredName = element.value;
83
- } else {
84
- // this.characteristics.push(service);
85
- }
86
- }.bind(this));
87
- devices.characteristics.forEach(function (element) {
88
- var service = new Characteristic(element, this);
89
- if (element.type.substring(0, 8) === '00000023' && element.description === "Name") {
90
- this.name = element.value;
91
- } else if (element.type.substring(0, 8) === '000000E3' && element.description === "Configured Name") {
92
- this.configuredName = element.value;
93
- } else {
94
- this.characteristics.push(service);
95
- }
96
- }.bind(this));
97
- if (this.configuredName) {
98
- this.name = this.configuredName;
99
- }
100
- // Uncomment to display services not defined
101
- // if (!this.service) {
102
- // console.log('Missing', devices);
103
- // }
104
- }
105
-
106
- Service.prototype.toList = function (context) {
107
- var descriptions;
108
- var getCharacteristics;
109
- var putCharacteristics = [];
110
- var eventRegisters = [];
111
- var characteristics = {};
112
- var fullName = context.name;
113
-
114
- if (this.name) {
115
- // Fix for #30
116
- if (context.manufacturer === "Nest" && (this.name === "Fan" || this.name === "Eco Mode")) {
117
- fullName = context.name + " - " + this.name;
118
- } else if (context.manufacturer === "Mitsubishi" && !fullName.includes(this.name)) {
119
- fullName = context.name + " - " + this.name;
120
- } else if (context.manufacturer === "Allterco") {
121
- fullName = context.name + " - " + this.name;
122
- } else {
123
- context.name = this.name;
124
- fullName = context.name;
125
- }
126
- }
127
-
128
- for (var index in this.characteristics) {
129
- var characteristic = this.characteristics[index];
130
- // debug("characteristic", characteristic)
131
- // debug("perms", context.opt);
132
- // debug("perms", (context.opt ? "perms" + context.opt.perms + characteristic.perms.includes(context.opt.perms) : "noperms"));
133
- if (characteristic.type !== '00000023' && characteristic.perms && (context.opt ? characteristic.perms.includes(context.opt.perms) : true)) {
134
- // debug("Yes", context.name, characteristic.description, characteristic.perms);
135
- descriptions = (descriptions ? descriptions + ', ' : '') + characteristic.description.replace(/ /g, "").replace(/\./g, "_");
136
- getCharacteristics = (getCharacteristics ? getCharacteristics + ',' : '') + characteristic.getCharacteristic;
137
- // characteristics = (characteristics ? characteristics + ',' : '') + characteristic.characteristic;
138
- characteristics = Object.assign(characteristics, characteristic.characteristic);
139
- putCharacteristics = putCharacteristics.concat(characteristic.putCharacteristic);
140
- eventRegisters = eventRegisters.concat(characteristic.eventRegister);
141
- } else {
142
- // debug("No", context.name, characteristic.description, characteristic.perms);
143
- }
144
- }
145
- if (this.service && descriptions) {
146
- return ({
147
- homebridge: context.homebridge,
148
- host: context.host,
149
- port: context.port,
150
- id: context.id,
151
- manufacturer: context.manufacturer,
152
- aid: this.aid,
153
- type: this.type,
154
- name: fullName,
155
- service: this.service,
156
- fullName: fullName + ' - ' + this.service,
157
- sortName: fullName + ':' + this.service,
158
- uniqueId: context.homebridge + this.id + context.manufacturer + fullName + this.type,
159
- descriptions: descriptions,
160
- characteristics: characteristics,
161
- getCharacteristics: getCharacteristics,
162
- eventRegisters: eventRegisters
163
- });
164
- }
165
- };
166
-
167
- function _normalizeName(id) {
168
- switch (id) {
169
- case "00000111":
170
- return ("Camera Control");
171
- case "00000088":
172
- return ("Stateful Programmable Switch");
173
- case "000000A1":
174
- return ("Bridge Configuration");
175
- case "00000062":
176
- return ("Bridging State");
177
- case "00000055":
178
- return ("Pairing");
179
- case "000000A2":
180
- return ("Protocol Information");
181
- case "0000005A":
182
- return ("Relay");
183
- case "00000099":
184
- return ("Time Information");
185
- case "00000056":
186
- return ("Tunneled BTLEAccessory Service");
187
- case "00000129":
188
- return ("Data Stream Transport Management");
189
- case "00000122":
190
- return ("Target Control Management");
191
- case "00000125":
192
- return ("Target Control");
193
- case "00000127":
194
- return ("Audio Stream Management");
195
- case "00000133":
196
- return ("Siri");
197
- case "000000D8":
198
- return ("Television");
199
- case "000000D9":
200
- return ("Input Source");
201
- case "000000DA":
202
- return ("Access Control");
203
- case "0000003E":
204
- return ("Accessory Information");
205
- case "000000BB":
206
- return ("Air Purifier");
207
- case "0000008D":
208
- return ("Air Quality Sensor");
209
- case "00000096":
210
- return ("Battery Service");
211
- case "00000110":
212
- return ("Camera RTPStream Management");
213
- case "00000097":
214
- return ("Carbon Dioxide Sensor");
215
- case "0000007F":
216
- return ("Carbon Monoxide Sensor");
217
- case "00000080":
218
- return ("Contact Sensor");
219
- case "00000081":
220
- return ("Door");
221
- case "00000121":
222
- return ("Doorbell");
223
- case "00000040":
224
- return ("Fan");
225
- case "000000B7":
226
- return ("Fan v2");
227
- case "000000BA":
228
- return ("Filter Maintenance");
229
- case "000000D7":
230
- return ("Faucet");
231
- case "00000041":
232
- return ("Garage Door Opener");
233
- case "000000BC":
234
- return ("Heater Cooler");
235
- case "000000BD":
236
- return ("Humidifier Dehumidifier");
237
- case "00000082":
238
- return ("Humidity Sensor");
239
- case "000000CF":
240
- return ("Irrigation System");
241
- case "00000083":
242
- return ("Leak Sensor");
243
- case "00000084":
244
- return ("Light Sensor");
245
- case "00000043":
246
- return ("Lightbulb");
247
- case "00000044":
248
- return ("Lock Management");
249
- case "00000045":
250
- return ("Lock Mechanism");
251
- case "00000112":
252
- return ("Microphone");
253
- case "00000085":
254
- return ("Motion Sensor");
255
- case "00000086":
256
- return ("Occupancy Sensor");
257
- case "00000047":
258
- return ("Outlet");
259
- case "0000007E":
260
- return ("Security System");
261
- case "000000CC":
262
- return ("Service Label");
263
- case "000000B9":
264
- return ("Slat");
265
- case "00000087":
266
- return ("Smoke Sensor");
267
- case "00000228":
268
- return ("Smart Speaker");
269
- case "00000113":
270
- return ("Speaker");
271
- case "00000089":
272
- return ("Stateless Programmable Switch");
273
- case "00000049":
274
- return ("Switch");
275
- case "0000008A":
276
- return ("Temperature Sensor");
277
- case "0000004A":
278
- return ("Thermostat");
279
- case "000000D0":
280
- return ("Valve");
281
- case "0000008B":
282
- return ("Window");
283
- case "0000008C":
284
- return ("Window Covering");
285
- case "0000021A":
286
- return ("Camera Operating Mode");
287
- case "00000204":
288
- return ("Camera Event Recording Management");
289
- case "0000020A":
290
- return ("WiFi Router");
291
- case "0000020F":
292
- return ("WiFi Satellite");
293
- case "00000221":
294
- return ("Power Management");
295
- case "00000203":
296
- return ("Transfer Transport Management");
297
- case "00000012":
298
- return ("Heartrate");
299
- // Eve types
300
- case "B77831FD":
301
- return ("Air Pressure Service");
302
- case "E863F007":
303
- return ("History Service");
304
- default:
305
- debug("Missing HB Type", id);
306
- }
307
- }
@@ -1,156 +0,0 @@
1
- var debug = require('debug')('register');
2
-
3
- module.exports = {
4
- registerEv: registerEv,
5
- registerCt: registerCt
6
- };
7
-
8
- function registerEv(homebridge, devices) {
9
- return register(homebridge, devices, 'ev');
10
- }
11
-
12
- function registerCt(homebridge, devices) {
13
- return register(homebridge, devices, 'pw');
14
- }
15
-
16
- function register(homebridge, devices, perms) {
17
- // debug('Discovered', devices);
18
- var events = [];
19
- devices.forEach(function(element) {
20
- // debug('Device', element);
21
- events = events.concat(_instance(element, perms));
22
- });
23
- return (events);
24
- }
25
-
26
- function _instance(instance, perms) {
27
- // debug('Accessories', instance.accessories.accessories);
28
- var events = [];
29
- instance.accessories.accessories.forEach(function(accessory) {
30
- // debug('Accessory', instance.instance.txt);
31
- events = events.concat(_service({
32
- "host": instance.ipAddress,
33
- "port": instance.instance.port,
34
- "homebridge": instance.instance.txt.md,
35
- "id": instance.instance.txt.id,
36
- "aid": accessory.aid
37
- }, accessory.services, perms));
38
- });
39
- return (events);
40
- }
41
-
42
- function _service(context, accessory, perms) {
43
- var events = [];
44
- accessory.forEach(function(service) {
45
- // debug('Service', service);
46
- switch (service.type.substring(0, 8)) {
47
- case "00000043": // Lightbulb
48
- case "00000047": // Outlet
49
- case "00000049": // Switch
50
- case "00000040": // Fan
51
- case "0000008C": // WindowCovering
52
- case "0000008A": // TemperatureSensor
53
- case "000000B7": // Fan 2 aka Dyson
54
- case "00000041": // Garage Door
55
- case "000000D0": // Valve aka sprinkler
56
- // case "0000003E": // AccessoryInformation
57
- case "0000004A": // Thermostat
58
- case "00000080": // Contact Sensor
59
- case "00000085": // Motion Sensor
60
- case "00000111": // Camera
61
- // debug('Supported Service', service);
62
- events = events.concat(_characteristics(context, service, perms));
63
- // debug("Events", events);
64
- break;
65
- case "0000003E": // AccessoryInformation
66
- _name(context, service);
67
- // debug("Events", events);
68
- break;
69
- default:
70
- }
71
- });
72
- return (events);
73
- }
74
-
75
- function _characteristics(context, service, perms) {
76
- // debug("Char", service, Array.isArray(service));
77
-
78
- var events = [];
79
- service.characteristics.forEach(function(characteristic) {
80
- switch (characteristic.type.substring(0, 8)) {
81
- case "00000020": // manufacturer
82
- context.manufacturer = characteristic.value;
83
- break;
84
- case "00000023": // name
85
- context.name = characteristic.value;
86
- break;
87
- }
88
-
89
- if (characteristic.perms.includes(perms)) {
90
- context.iid = characteristic.iid;
91
- context.function = characteristic.description;
92
- context.service = service.type.substring(0, 8);
93
- context.characteristic = characteristic.type.substring(0, 8);
94
- context.deviceType = _normalizeName(context.service);
95
- // debug("Register", context);
96
- context.fullName = context.name + ' - ' + _normalizeName(context.service) + ' - ' + context.function;
97
- context.sortName = context.name + ':' + _normalizeName(context.service) + ':' + context.function;
98
- context.uniqueId = context.homebridge + context.id + context.manufacturer + context.name + context.service + context.characteristic;
99
- // debug("Perms ", context.fullName, characteristic.perms);
100
- events.push(JSON.parse(JSON.stringify(context)));
101
- }
102
- });
103
- // debug("Char Events", events);
104
- return (events);
105
- }
106
-
107
- function _name(context, service) {
108
- // debug("Char", service, Array.isArray(service));
109
-
110
- var manufacturer, name;
111
- service.characteristics.forEach(function(characteristic) {
112
- switch (characteristic.type.substring(0, 8)) {
113
- case "00000020": // manufacturer
114
- context.manufacturer = characteristic.value;
115
- break;
116
- case "00000023": // name
117
- context.name = characteristic.value;
118
- break;
119
- }
120
- });
121
- // debug("Char Events", events);
122
- // return ({ "manufacturer": manufacturer, "name": name});
123
- }
124
-
125
- function _normalizeName(id) {
126
- switch (id) {
127
- case "00000043": // Lightbulb
128
- return ("Lightbulb");
129
- case "00000047": // Outlet
130
- return ("Outlet");
131
- case "00000049": // Switch
132
- return ("Switch");
133
- case "000000B7": // Fan 2 aka Dyson
134
- case "00000040": // Fan
135
- return ("Fan");
136
- case "0000008C": // WindowCovering
137
- return ("Blinds");
138
- case "0000008A": // TemperatureSensor
139
- return ("Temperature");
140
- case "00000041": // Garage Door
141
- return ("Garage Door");
142
- case "000000D0": // Valve aka sprinkler
143
- return ("Sprinkler");
144
- // case "0000003E": // AccessoryInformation
145
- case "0000004A": // Thermostat
146
- return ("Thermostat");
147
- case "00000080": // Contact Sensor
148
- return ("Contact");
149
- case "00000085": // Motion Sensor
150
- return ("Motion");
151
- case "00000111": // Camera
152
- return ("Camera");
153
- default:
154
- debug("Missing HB Type", id);
155
- }
156
- }