diff --git a/lib/api.js b/lib/api.js index d2aa1b3..738de79 100644 --- a/lib/api.js +++ b/lib/api.js @@ -20,7 +20,7 @@ function API() { this._dynamicPlatforms = {}; // this._dynamicPlatforms[pluginName.platformName] = platform constructor // expose the homebridge API version - this.version = 2.0; + this.version = 2.1; // expose the User class methods to plugins to get paths. Example: homebridge.user.storagePath() this.user = User; @@ -85,6 +85,18 @@ API.prototype.registerAccessory = function(pluginName, accessoryName, constructo } } +API.prototype.publishCameraAccessories = function(pluginName, accessories) { + for (var index in accessories) { + var accessory = accessories[index]; + if (!(accessory instanceof PlatformAccessory)) { + throw new Error(pluginName + " attempt to register an accessory that isn\'t PlatformAccessory!"); + } + accessory._associatedPlugin = pluginName; + } + + this.emit('publishCameraAccessories', accessories); +} + API.prototype.platform = function(name) { // if you passed the "short form" name like "Lockitron" instead of "homebridge-lockitron.Lockitron", diff --git a/lib/platformAccessory.js b/lib/platformAccessory.js index 1680823..382ef0d 100644 --- a/lib/platformAccessory.js +++ b/lib/platformAccessory.js @@ -130,8 +130,21 @@ PlatformAccessory.prototype.updateReachability = function(reachable) { } } +PlatformAccessory.prototype.configureCameraSource = function(cameraSource) { + this.cameraSource = cameraSource; + for (var index in cameraSource.services) { + var service = cameraSource.services[index]; + this.addService(service); + } +} + PlatformAccessory.prototype._prepareAssociatedHAPAccessory = function () { this._associatedHAPAccessory = new Accessory(this.displayName, this.UUID); + + if (this.cameraSource) { + this._associatedHAPAccessory.configureCameraSource(this.cameraSource); + } + this._associatedHAPAccessory._sideloadServices(this.services); this._associatedHAPAccessory.category = this.category; this._associatedHAPAccessory.reachable = this.reachable; diff --git a/lib/server.js b/lib/server.js index 2bf84c1..5e98e3c 100644 --- a/lib/server.js +++ b/lib/server.js @@ -15,6 +15,7 @@ var PlatformAccessory = require("./platformAccessory").PlatformAccessory; var BridgeSetupManager = require("./bridgeSetupManager").BridgeSetupManager; var log = require("./logger")._system; var Logger = require('./logger').Logger; +var mac = require("./util/mac"); 'use strict'; @@ -40,6 +41,10 @@ function Server(insecureAccess) { this._handleUnregisterPlatformAccessories(accessories); }.bind(this)); + this._api.on('publishCameraAccessories', function(accessories) { + this._handlePublishCameraAccessories(accessories); + }.bind(this)); + this._plugins = this._loadPlugins(); // plugins[name] = Plugin instance this._config = this._loadConfig(); this._cachedPlatformAccessories = this._loadCachedPlatformAccessories(); @@ -47,6 +52,7 @@ function Server(insecureAccess) { this._activeDynamicPlugins = {}; this._configurablePlatformPlugins = {}; + this._publishedCameras = {}; this._setupManager = new BridgeSetupManager(); this._setupManager.on('newConfig', this._handleNewConfig.bind(this)); @@ -97,14 +103,16 @@ Server.prototype._publish = function() { info.setCharacteristic(Characteristic.SerialNumber, bridgeConfig.serialNumber); this._printPin(bridgeConfig.pin); + + this._bridge.on('listening', function(port) { + log.info("Homebridge is running on port %s.", port); + }); + this._bridge.publish({ username: bridgeConfig.username || "CC:22:3D:E3:CE:30", - port: bridgeConfig.port || 51826, pincode: bridgeConfig.pin || "031-45-154", category: Accessory.Categories.BRIDGE }, this._allowInsecureAccess); - - log.info("Homebridge is running on port %s.", bridgeConfig.port || 51826); } Server.prototype._loadPlugins = function(accessories, platforms) { @@ -165,7 +173,6 @@ Server.prototype._loadConfig = function() { config.bridge = { "name": "Homebridge", "username": "CC:22:3D:E3:CE:30", - "port": 51826, "pin": "031-45-154" }; @@ -454,6 +461,34 @@ Server.prototype._handleUnregisterPlatformAccessories = function(accessories) { this._updateCachedAccessories(); } +Server.prototype._handlePublishCameraAccessories = function(accessories) { + var accessoryPin = (this._config.bridge || {}).pin || "031-45-154"; + + for (var index in accessories) { + var accessory = accessories[index]; + + accessory._prepareAssociatedHAPAccessory(); + var hapAccessory = accessory._associatedHAPAccessory; + var advertiseAddress = mac.generate(accessory.UUID); + + if (this._publishedCameras[advertiseAddress]) { + throw new Error("Camera accessory %s experienced an address collision.", accessory.displayName); + } else { + this._publishedCameras[advertiseAddress] = accessory; + } + + hapAccessory.on('listening', function(port) { + log.info("%s is running on port %s.", accessory.displayName, port); + }); + + hapAccessory.publish({ + username: advertiseAddress, + pincode: accessoryPin, + category: accessory.category + }, this._allowInsecureAccess); + } +} + Server.prototype._updateCachedAccessories = function() { var serializedAccessories = []; diff --git a/lib/util/mac.js b/lib/util/mac.js new file mode 100644 index 0000000..89eee74 --- /dev/null +++ b/lib/util/mac.js @@ -0,0 +1,18 @@ +var crypto = require('crypto'); + +'use strict'; + +module.exports = { + generate: generate +} + +function generate(data) { + var sha1sum = crypto.createHash('sha1'); + sha1sum.update(data); + var s = sha1sum.digest('hex'); + var i = -1; + return 'xx:xx:xx:xx:xx:xx'.replace(/[x]/g, function(c) { + i += 1; + return s[i]; + }).toUpperCase(); +}; \ No newline at end of file diff --git a/package.json b/package.json index e26965e..0597a3d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "homebridge", "description": "HomeKit support for the impatient", - "version": "0.3.4", + "version": "0.4.1", "scripts": { "dev": "DEBUG=* ./bin/homebridge -D -P example-plugins/ || true" }, @@ -20,13 +20,13 @@ "homebridge": "bin/homebridge" }, "engines": { - "node": ">=0.12.0" + "node": ">=4.3.2" }, "preferGlobal": true, "dependencies": { "chalk": "^1.1.1", "commander": "2.8.1", - "hap-nodejs": "0.3.2", + "hap-nodejs": "0.4.6", "semver": "5.0.3", "node-persist": "^0.0.8" }