99 Commits

Author SHA1 Message Date
Khaos Tian 8a35d75cb5 0.4.21 2017-07-01 22:02:04 -06:00
Khaos Tian c70cb8be07 Bump hap-nodejs version 2017-07-01 22:01:56 -06:00
Olivier Guerriat 7406f6c9f3 Added "limitations" to the README (#1338) 2017-06-10 12:09:09 -07:00
Brent Unkrich cbae68afdd updated formatting (#1284)
took out extra spaces and fixed capitalization.
2017-05-11 19:23:08 -07:00
Khaos Tian 495143e1a1 Update hap-nodejs version 2017-05-01 23:30:05 -07:00
Khaos Tian 7585cf3f83 0.4.19
Bump hap-nodejs version to add support for programmable switch label.
2017-04-16 17:35:44 -07:00
Khaos Tian d521755a49 0.4.18
Add support for updated programmable service profile.
2017-04-16 13:32:00 -07:00
Khaos Tian 6f4ce80aea Bump hap-nodejs version. 2017-04-07 22:06:17 -07:00
Stephan Esch efda0fac11 Added serverVersion to API; bumped API version to 2.2 (#1064)
* Added serverVersion to API; bumped API version to 2.1.1

* Fixed version number to 2.2
2017-01-13 09:48:56 -08:00
Khaos Tian 600760884d Address a metadata issue that blocks camera support. 2016-12-13 15:50:19 +08:00
Khaos Tian 3a4830ee57 Update hap-nodejs to support new services in iOS 10.2 2016-12-13 11:05:30 +08:00
Khaos Tian 582e00a6ef 0.4.12 2016-12-10 14:23:53 -08:00
Khaos Tian debba05d2f Merge pull request #967 from andig/patch-1
Upgrade hap-nodejs
2016-12-02 01:20:34 -08:00
andig 027a693c0d Update package.json 2016-12-02 10:19:58 +01:00
andig b5e1fc52a8 Upgrade hap-nodejs 2016-12-02 10:18:49 +01:00
Khaos Tian f17fe59590 Fix an warning in nodejs v7 2016-11-29 18:42:17 -08:00
Khaos Tian 69e3ed5ee4 Merge pull request #491 from straccio/master
Added pluginPath based on npm
2016-11-28 13:21:27 -08:00
Khaos Tian 3354842e81 Merge pull request #917 from crzcrz/master
Use chalk instead of hardcoded ANSI codes
2016-11-28 13:17:35 -08:00
straccio e5e2a400ec Merge remote-tracking branch 'nfarina/master'
# Conflicts:
#	lib/plugin.js
2016-11-28 13:36:00 +01:00
Khaos Tian 4884087041 0.4.10 2016-11-27 15:24:43 -08:00
Khaos Tian e1867b2bc0 Improve error handling. 2016-11-27 15:24:27 -08:00
Khaos Tian 4d0f9d86f6 Merge pull request #941 from djMax/master
Allow externally specified config
2016-11-21 12:04:57 -08:00
Max Metral ecda18029f Allow externally specified config 2016-11-21 14:58:39 -05:00
straccio 7acac442a8 Merge remote-tracking branch 'nfarina/master' 2016-11-21 09:12:23 +01:00
Khaos Tian efc570e5a9 Update example plugin
Add comment for service name.
2016-11-18 00:33:36 -08:00
straccio 7955049337 Merge remote-tracking branch 'nfarina/master' 2016-11-14 11:24:01 +01:00
Stanislav Kljuhhin 8c6cb53dcb Use chalk instead of hardcoded ANSI codes
Improves the readability of the source code and prevents the raw ANSI codes from appearing in the log, if ran as a systemd service.
2016-11-13 16:29:10 +01:00
Khaos Tian b6cfe3ba7c 0.4.9 2016-11-09 18:11:57 -08:00
Khaos Tian f836d4a42c Bump hap-nodejs version to fix #791 2016-11-09 18:11:41 -08:00
straccio f893322887 Merge remote-tracking branch 'nfarina/master' 2016-11-04 10:05:11 +01:00
Khaos Tian 63ab1025e9 Update hap-nodejs to allow homebridge work with nodejs v4.x 2016-11-03 12:20:46 -07:00
straccio 9a25a363d4 Merge remote-tracking branch 'nfarina/master' 2016-11-03 17:05:53 +01:00
Khaos Tian dc43d0b7c4 Update hap-nodejs
This version requires node v5.10.0 or later.
2016-11-01 18:33:59 -07:00
straccio 1513e5398f Merge remote-tracking branch 'nfarina/master' 2016-10-11 15:52:58 +02:00
Khaos Tian 7c3543ba61 Merge pull request #839 from rxseger/collision-name
Fix camera name in collision error message
2016-10-09 17:14:29 -07:00
rxseger 5adb5f3282 Fix camera name in collision error message 2016-10-09 23:36:53 +00:00
straccio ffe343c65f Merge remote-tracking branch 'nfarina/master' 2016-10-03 09:24:28 +02:00
Khaos Tian fedd341970 0.4.6 2016-10-01 16:48:05 -07:00
Khaos Tian c7c9aa0150 Bump hap-nodejs version. 2016-10-01 16:48:01 -07:00
straccio a2baa93801 Merge remote-tracking branch 'nfarina/master' 2016-09-29 09:00:45 +02:00
Khaos Tian e3e08414f6 0.4.5 2016-09-28 17:11:01 -07:00
Khaos Tian ea9df45d2d Add back the ability to designate the port homebridge is running. 2016-09-28 17:10:52 -07:00
Khaos Tian 7425f8beca 0.4.4 2016-09-28 12:40:35 -07:00
straccio 8192fc2672 Merge remote-tracking branch 'nfarina/master' 2016-09-28 08:19:30 +02:00
Khaos Tian dbb7b89cf9 0.4.3 2016-09-27 17:01:08 -07:00
Khaos Tian 4f000485db Bump hap-nodejs again... 2016-09-27 17:01:00 -07:00
Khaos Tian c0884f484e 0.4.2 2016-09-27 12:36:29 -07:00
Khaos Tian 363c997058 Bump hap-nodejs version 2016-09-27 12:36:23 -07:00
straccio 332385d605 Merge remote-tracking branch 'nfarina/master' 2016-09-27 08:38:18 +02:00
Khaos Tian 0ccd80c8e7 0.4.1 2016-09-26 20:32:06 -07:00
Khaos Tian ef8fe5ced2 Update hap-nodejs version to fix side load problem 2016-09-26 20:31:55 -07:00
Khaos Tian 4a531ede5c Merge pull request #805 from nfarina/ip-cam
IP Camera support for homebridge
2016-09-26 14:34:35 -07:00
Khaos Tian ff35ece65c 0.4.0 2016-09-26 14:22:22 -07:00
Khaos Tian 66ea6e640d Minor Tweak 2016-09-26 14:15:12 -07:00
Khaos Tian ecd06d7239 Bump api version 2016-09-26 13:19:50 -07:00
Khaos Tian c89ff97ac5 init design 2016-09-26 13:01:29 -07:00
Khaos Tian ceec4c74fd Merge pull request #803 from nfarina/use-hap-0.4
Use hap-nodejs 0.4.0
2016-09-26 12:02:32 -07:00
Jon Maddox 925c1630c4 bump hap-nodejs to 0.4.0 2016-09-26 10:46:21 -04:00
straccio 41c53f8f10 Merge remote-tracking branch 'nfarina/master' 2016-09-20 09:17:15 +02:00
Khaos Tian 4eabc4ad52 Merge pull request #593 from PatchworkBoy/patch-1
Ref #582
2016-09-18 21:37:49 -07:00
Khaos Tian c0859a29d3 Merge pull request #764 from alessiodionisi/new-bridge-configs
New bridge configs
2016-09-18 21:37:18 -07:00
Khaos Tian c15707e875 Merge pull request #778 from nrobinson2000/patch-1
Some changes to the README
2016-09-18 21:36:42 -07:00
Nathan Robinson 8c476b45a0 Update README.md 2016-09-18 21:13:38 -04:00
Nick Farina f49229d73c Update README to reflect the new iOS 10 Home app. 2016-09-15 21:05:39 -07:00
Khaos Tian fbccc031f4 Merge pull request #770 from kcjonson/patch-1
Update README.md
2016-09-15 14:57:11 -07:00
Kevin Jonson d70fa741d8 Update README.md 2016-09-15 14:07:09 -07:00
Alessio Dionisi 4740bf1fc5 New bridge configs
"bridge": {
    "manufacturer": "Manufacturer here",
    "serialNumber": "Serial number here",
    "model": "Model here"
}
2016-09-13 13:54:37 +02:00
Khaos Tian da57b29972 Merge pull request #758 from cflurin/master
Warning config.json not found
2016-09-06 08:28:36 -07:00
cflurin 5944365bc6 Warning config.json not found 2016-09-06 14:49:53 +02:00
Khaos Tian a8908fd9b8 Merge pull request #714 from EdJoPaTo/platformLog
optimized logging of the SamplePlatform example
2016-07-30 18:41:01 -07:00
Khaos Tian 8ef7e62094 Merge pull request #715 from EdJoPaTo/multiAccessories
fixed SamplePlatform crashes
2016-07-30 18:40:35 -07:00
Edgar To 15c8eaaf29 use of the own log method instead of the general console.log(); added accessory.displayName to the log output if possible/ useful 2016-07-24 22:43:21 +02:00
Edgar To e6648375c7 different add times will create different UUIDs -> no crash with the second add call 2016-07-24 22:38:05 +02:00
straccio 4251b15291 Merge remote-tracking branch 'nfarina/master' 2016-05-31 08:52:59 +02:00
Khaos Tian a52bc9e437 Merge pull request #642 from alexbain/patch-1
Add note about --unsafe-perm
2016-05-22 18:35:12 -07:00
Alex Bain b78c081cd4 Add note about --unsafe-perm
I received the following error when trying to install homebridge on a RaspberryPi. Assuming I'm not the first or the last to see this error, I thought adding a note to README about the --unsafe-perm flag would aid others.
2016-05-22 18:01:32 -07:00
straccio 3f2cd08383 Merge remote-tracking branch 'nfarina/master' 2016-05-02 16:44:42 +02:00
Khaos Tian 87050a2267 update hap-nodejs dependency for node v6 2016-04-29 10:23:15 -07:00
straccio c8cb0731ff Merge remote-tracking branch 'nfarina/master' 2016-04-11 09:45:54 +02:00
Khaos Tian 35dfaabc69 update hap-nodejs dependency 2016-04-08 23:51:03 -07:00
Khaos Tian 77ce39e157 0.3.3 2016-04-08 23:50:34 -07:00
Khaos Tian 0af8a43dc9 Expose platform accessory category to hap-nodejs
Fix an error in plugin config look up
2016-04-08 23:50:18 -07:00
Marci f203a2ac6f Ref #582
Ref#582 Add ‘--unsafe-perm’ flag to npm install command to get round all the .gyp warns etc.
2016-03-31 15:50:50 +01:00
straccio 39af2ebbef Merge remote-tracking branch 'nfarina/master'
# Conflicts:
#	lib/logger.js
2016-03-21 08:43:36 +01:00
Khaos Tian 620c8473b8 #572 2016-03-20 22:12:47 -07:00
straccio f73783787d Merge remote-tracking branch 'nfarina/master' 2016-03-11 08:18:56 +01:00
straccio b94c3caa3b Changed color for logging timestamp to white. 2016-03-08 15:59:44 +01:00
straccio 1a710badef Merge remote-tracking branch 'nfarina/master' 2016-03-08 08:45:04 +01:00
straccio 73fdec5928 Revert to upstream/master, no need to skip cached accessories 2016-03-08 08:44:52 +01:00
straccio 911f088df9 A way to skip cached accessories from being loaded in HAP 2016-03-07 17:32:18 +01:00
straccio 6fade3c3cc Merge remote-tracking branch 'nfarina/master' 2016-03-07 17:28:41 +01:00
straccio 191c75c281 Merge remote-tracking branch 'upstream/master' 2016-03-02 08:58:03 +01:00
straccio 1fb58be2b9 ignore idea 2016-03-02 08:47:15 +01:00
straccio ca66cc3499 Merge branch 'master' of https://github.com/straccio/homebridge 2016-02-29 09:06:32 +01:00
straccio 6ae2a19d37 missed ";" 2016-02-29 09:05:42 +01:00
straccio ffe4232c3b Added pluginPath based on npm 2016-02-29 09:05:42 +01:00
straccio fa9561d98a missed ";" 2016-02-22 10:01:25 +01:00
straccio 16a29f302d Merge remote-tracking branch 'upstream/master' 2016-02-22 08:53:35 +01:00
straccio 40fc7acbed Added pluginPath based on npm 2016-01-27 07:40:26 +01:00
11 changed files with 198 additions and 91 deletions
+2
View File
@@ -10,3 +10,5 @@ npm-debug.log
# Ignore any extra plugins in the example directory that aren't in Git already
# (this is a sandbox for the user)
example-plugins
.idea
+15 -12
View File
@@ -29,7 +29,11 @@ You can also chat with us in our nascent [Slack instance](http://homebridge-slac
Homebridge is published through [NPM](https://www.npmjs.com/package/homebridge) and should be installed "globally" by typing:
sudo npm install -g homebridge
sudo npm install -g --unsafe-perm homebridge
You may need to use the `--unsafe-perm` flag if you receive an error similar to this:
gyp WARN EACCES user "root" does not have permission to access the dev dir "/root/.node-gyp/5.5.0"
Now you should be able to run Homebridge:
@@ -45,9 +49,9 @@ Once you've installed a Plugin or two, you can run Homebridge again:
However, Homebridge won't do anything until you've created a `config.json` file containing your accessories and/or platforms. You can start by copying and modifying the included `config-sample.json` file which includes declarations for some example accessories and platforms. Each Plugin will have its own expected configuration; the documentation for Plugins should give you some real-world examples for that plugin.
**NOTE**: Your `config.json` file MUST live in your home directory inside `.homebridge`. The full error message will contain the exact path where your config is expected to be found.
**NOTE**: Your `config.json` file MUST be inside of `.homebridge`, which is inside of your home folder. On macOS and Linux, the full path for your `config.json` would be `~/.homebridge/config.json`. Any error messages will contain the exact path where your config is expected to be found.
**REALLY IMPORTANT**: You must use a "plain text" editor to create or modify `config.json`. Do NOT use apps like TextEdit on Mac or Wordpad on Windows; these apps will corrupt the formatting of the file in hard-to-debug ways. I suggest using the free [Atom text editor](http://atom.io).
**REALLY IMPORTANT**: You must use a "plain text" editor to create or modify `config.json`. Do NOT use apps like TextEdit on Mac or Wordpad on Windows. Apps like these will corrupt the formatting of the file in hard-to-debug ways, making improper `"` signs is an example. I suggest using the free [Atom text editor](http://atom.io).
Once you've added your config file, you should be able to run Homebridge again:
@@ -79,15 +83,11 @@ You can explore all available plugins at the NPM website by [searching for the k
# Adding Homebridge to iOS
HomeKit is actually not an app; it's a "database" similar to HealthKit and PassKit. But where HealthKit has the companion _Health_ app and PassKit has _Passbook_, Apple has supplied no app for managing your HomeKit database (at least [not yet](http://9to5mac.com/2015/05/20/apples-planned-ios-9-home-app-uses-virtual-rooms-to-manage-homekit-accessories/)). However, the HomeKit API is open for developers to write their own apps for adding devices to HomeKit.
HomeKit itself is actually not an app; it's a "database" similar to HealthKit and PassKit. Where HealthKit has the companion _Health_ app and PassKit has _Passbook_, HomeKit has the _Home_ app, introduced with iOS 10.
Fortunately, there are now a few apps in the App Store that can manage your HomeKit devices. The most comprehensive one I've used is [MyTouchHome](https://itunes.apple.com/us/app/mytouchhome/id965142360?mt=8&at=11lvmd&ct=mhweb) which costs $2.
If you are a member of the iOS developer program, you might also find Apple's [HomeKit Catalog](https://developer.apple.com/library/ios/samplecode/HomeKitCatalog/Introduction/Intro.html) app to be useful, as it provides straightforward and comprehensive management of all HomeKit database "objects".
There are also some free apps that work OK. Try [Insteon+](https://itunes.apple.com/US/app/id919270334?mt=8) or [Lutron](https://itunes.apple.com/us/app/lutron-app-for-caseta-wireless/id886753021?mt=8) or a number of others.
If you are a member of the iOS developer program, I highly recommend Apple's [HomeKit Catalog](https://developer.apple.com/library/ios/samplecode/HomeKitCatalog/Introduction/Intro.html) app, as it is reliable and comprehensive and free (and open source).
Once you've gotten a HomeKit app running on your iOS device, it should "discover" the single accessory "Homebridge", assuming that you're still running Homebridge and you're on the same Wifi network. Adding this accessory will automatically add all accessories and platforms defined in `config.json`.
Using the Home app (or most other HomeKit apps), you should be able to add the single accessory "Homebridge", assuming that you're still running Homebridge and you're on the same Wifi network. Adding this accessory will automatically add all accessories and platforms defined in `config.json`.
When you attempt to add Homebridge, it will ask for a "PIN code". The default code is `031-45-154` (but this can be changed, see `config-sample.json`).
@@ -150,6 +150,11 @@ The following errors are experienced when starting Homebridge and can be safely
*** WARNING *** For more information see http://0pointerde/avahi-compat?s=libdns_sd&e=nodejs&f=DNSServiceRegister
```
### Limitations
* One installation of Homebridge can only expose 100 accessories due to a HomeKit limit. You can however run multiple Homebridge instances by pointing them to different config and persistence paths (see issue #827).
* Once an accessory has been added to the Home app, changing its name via Homebridge won't be automatically reflected in iOS. You must change it via the Home app as well.
# Why Homebridge?
Technically, the device manufacturers should be the ones implementing the HomeKit API. And I'm sure they will - eventually. When they do, this project will be obsolete, and I hope that happens soon. In the meantime, Homebridge is a fun way to get a taste of the future, for those who just can't bear to wait until "real" HomeKit devices are on the market.
@@ -157,5 +162,3 @@ Technically, the device manufacturers should be the ones implementing the HomeKi
# Credit
The original HomeKit API work was done by [KhaosT](http://twitter.com/khaost) in his [HAP-NodeJS](https://github.com/KhaosT/HAP-NodeJS) project.
@@ -21,14 +21,15 @@ module.exports = function(homebridge) {
// config may be null
// api may be null if launched from old homebridge version
function SamplePlatform(log, config, api) {
console.log("SamplePlatform Init");
log("SamplePlatform Init");
var platform = this;
this.log = log;
this.config = config;
this.accessories = [];
this.requestServer = http.createServer(function(request, response) {
if (request.url === "/add") {
this.addAccessory();
this.addAccessory(new Date().toISOString());
response.writeHead(204);
response.end();
}
@@ -47,7 +48,7 @@ function SamplePlatform(log, config, api) {
}.bind(this));
this.requestServer.listen(18081, function() {
console.log("Server Listening...");
platform.log("Server Listening...");
});
if (api) {
@@ -58,7 +59,7 @@ function SamplePlatform(log, config, api) {
// Platform Plugin should only register new accessory that doesn't exist in homebridge after this event.
// Or start discover new accessories
this.api.on('didFinishLaunching', function() {
console.log("Plugin - DidFinishLaunching");
platform.log("DidFinishLaunching");
}.bind(this));
}
}
@@ -67,7 +68,8 @@ function SamplePlatform(log, config, api) {
// Developer can configure accessory at here (like setup event handler)
// Update current value
SamplePlatform.prototype.configureAccessory = function(accessory) {
console.log("Plugin - Configure Accessory: " + accessory.displayName);
this.log(accessory.displayName, "Configure Accessory");
var platform = this;
// set the accessory to reachable if plugin can currently process the accessory
// otherwise set to false and update the reachability later by invoking
@@ -75,7 +77,7 @@ SamplePlatform.prototype.configureAccessory = function(accessory) {
accessory.reachable = true;
accessory.on('identify', function(paired, callback) {
console.log("Identify!!!");
platform.log(accessory.displayName, "Identify!!!");
callback();
});
@@ -83,7 +85,7 @@ SamplePlatform.prototype.configureAccessory = function(accessory) {
accessory.getService(Service.Lightbulb)
.getCharacteristic(Characteristic.On)
.on('set', function(value, callback) {
console.log("Light -> " + value);
platform.log(accessory.displayName, "Light -> " + value);
callback();
});
}
@@ -94,8 +96,8 @@ SamplePlatform.prototype.configureAccessory = function(accessory) {
//Handler will be invoked when user try to config your plugin
//Callback can be cached and invoke when nessary
SamplePlatform.prototype.configurationRequestHandler = function(context, request, callback) {
console.log("Context: ", JSON.stringify(context));
console.log("Request: ", JSON.stringify(request));
this.log("Context: ", JSON.stringify(context));
this.log("Request: ", JSON.stringify(request));
// Check the request response
if (request && request.response && request.response.inputs && request.response.inputs.name) {
@@ -173,28 +175,26 @@ SamplePlatform.prototype.configurationRequestHandler = function(context, request
// Sample function to show how developer can add accessory dynamically from outside event
SamplePlatform.prototype.addAccessory = function(accessoryName) {
console.log("Add Accessory");
this.log("Add Accessory");
var platform = this;
var uuid;
if (!accessoryName) {
accessoryName = "Test Accessory"
}
uuid = UUIDGen.generate(accessoryName);
var newAccessory = new Accessory(accessoryName, uuid);
newAccessory.on('identify', function(paired, callback) {
console.log("Identify!!!");
platform.log(accessory.displayName, "Identify!!!");
callback();
});
// Plugin can save context on accessory
// To help restore accessory in configureAccessory()
// newAccessory.context.something = "Something"
// Make sure you provided a name for service otherwise it may not visible in some HomeKit apps.
newAccessory.addService(Service.Lightbulb, "Test Light")
.getCharacteristic(Characteristic.On)
.on('set', function(value, callback) {
console.log("Light -> " + value);
platform.log(accessory.displayName, "Light -> " + value);
callback();
});
@@ -203,7 +203,7 @@ SamplePlatform.prototype.addAccessory = function(accessoryName) {
}
SamplePlatform.prototype.updateAccessoriesReachability = function() {
console.log("Update Reachability");
this.log("Update Reachability");
for (var index in this.accessories) {
var accessory = this.accessories[index];
accessory.updateReachability(false);
@@ -212,8 +212,8 @@ SamplePlatform.prototype.updateAccessoriesReachability = function() {
// Sample function to show how developer can remove accessory dynamically from outside event
SamplePlatform.prototype.removeAccessory = function() {
console.log("Remove Accessory");
this.log("Remove Accessory");
this.api.unregisterPlatformAccessories("homebridge-samplePlatform", "SamplePlatform", this.accessories);
this.accessories = [];
}
}
+17 -1
View File
@@ -5,6 +5,7 @@ var hapLegacyTypes = require("hap-nodejs/accessories/types.js");
var log = require("./logger")._system;
var User = require("./user").User;
var PlatformAccessory = require("./platformAccessory").PlatformAccessory;
var serverVersion = require("./version");
// The official homebridge API is the object we feed the plugin's exported initializer function.
@@ -20,7 +21,10 @@ function API() {
this._dynamicPlatforms = {}; // this._dynamicPlatforms[pluginName.platformName] = platform constructor
// expose the homebridge API version
this.version = 2.0;
this.version = 2.2;
// expose the homebridge server version
this.serverVersion = serverVersion;
// expose the User class methods to plugins to get paths. Example: homebridge.user.storagePath()
this.user = User;
@@ -85,6 +89,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",
+1 -1
View File
@@ -178,7 +178,7 @@ BridgeSetupSession.prototype.handleManageAccessory = function(request) {
BridgeSetupSession.prototype.sendResponse = function(response) {
if (this.validSession) {
var serializedReponse = JSON.stringify(response);
var respData = Buffer(serializedReponse).toString('base64');
var respData = new Buffer(serializedReponse).toString('base64');
this.lastResponse = respData;
setTimeout(function() {
this.controlChar.setValue(respData);
+10 -10
View File
@@ -31,7 +31,7 @@ Logger.prototype.debug = function(msg) {
if (DEBUG_ENABLED)
this.log.apply(this, ['debug'].concat(Array.prototype.slice.call(arguments)));
}
Logger.prototype.info = function(msg) {
this.log.apply(this, ['info'].concat(Array.prototype.slice.call(arguments)));
}
@@ -43,35 +43,35 @@ Logger.prototype.warn = function(msg) {
Logger.prototype.error = function(msg) {
this.log.apply(this, ['error'].concat(Array.prototype.slice.call(arguments)));
}
Logger.prototype.log = function(level, msg) {
msg = util.format.apply(util, Array.prototype.slice.call(arguments, 1));
func = console.log;
if (level == 'debug') {
msg = chalk.gray(msg);
}
else if (level == 'warn') {
msg = chalk.yellow(msg);
func = console.error;
func = console.error;
}
else if (level == 'error') {
msg = chalk.bold.red(msg);
func = console.error;
}
// prepend prefix if applicable
if (this.prefix)
msg = chalk.cyan("[" + this.prefix + "]") + " " + msg;
// prepend timestamp
var date = new Date();
msg = chalk.black("[" + date.toLocaleString() + "]") + " " + msg;
msg = chalk.white("[" + date.toLocaleString() + "]") + " " + msg;
func(msg);
}
Logger.withPrefix = function(prefix) {
if (!loggerCache[prefix]) {
@@ -87,6 +87,6 @@ Logger.withPrefix = function(prefix) {
log.prefix = logger.prefix;
loggerCache[prefix] = log;
}
return loggerCache[prefix];
}
+16
View File
@@ -130,9 +130,23 @@ 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;
this._associatedHAPAccessory.on('identify', function(paired, callback) {
if (this.listeners('identify').length > 0) {
@@ -171,6 +185,7 @@ PlatformAccessory.prototype._dictionaryPresentation = function() {
characteristicPresentation.UUID = characteristic.UUID;
characteristicPresentation.props = characteristic.props;
characteristicPresentation.value = characteristic.value;
characteristicPresentation.eventOnlyCharacteristic = characteristic.eventOnlyCharacteristic;
characteristics.push(characteristicPresentation);
}
@@ -200,6 +215,7 @@ PlatformAccessory.prototype._configFromData = function(data) {
for (var cIndex in service.characteristics) {
var characteristic = service.characteristics[cIndex];
var hapCharacteristic = new Characteristic(characteristic.displayName, characteristic.UUID, characteristic.props);
hapCharacteristic.eventOnlyCharacteristic = characteristic.eventOnlyCharacteristic;
hapCharacteristic.value = characteristic.value;
characteristics.push(hapCharacteristic);
}
+30 -27
View File
@@ -13,7 +13,7 @@ module.exports = {
/**
* Homebridge Plugin.
*
*
* Allows for discovering and loading installed Homebridge plugins.
*/
@@ -28,39 +28,39 @@ Plugin.prototype.name = function() {
Plugin.prototype.load = function(options) {
options = options || {};
// does this plugin exist at all?
if (!fs.existsSync(this.pluginPath)) {
throw new Error("Plugin " + this.pluginPath + " was not found. Make sure the module '" + this.pluginPath + "' is installed.");
}
// attempt to load package.json
var pjson = Plugin.loadPackageJSON(this.pluginPath);
// very temporary fix for first wave of plugins
if (pjson.peerDepdendencies && (!pjson.engines || !pjson.engines.homebridge)) {
var engines = pjson.engines || {}
engines.homebridge = pjson.peerDepdendencies.homebridge;
pjson.engines = engines;
}
// pluck out the HomeBridge version requirement
if (!pjson.engines || !pjson.engines.homebridge) {
throw new Error("Plugin " + this.pluginPath + " does not contain the 'homebridge' package in 'engines'.");
}
var versionRequired = pjson.engines.homebridge;
// make sure the version is satisfied by the currently running version of HomeBridge
if (!semver.satisfies(version, versionRequired)) {
throw new Error("Plugin " + this.pluginPath + " requires a HomeBridge version of " + versionRequired + " which does not satisfy the current HomeBridge version of " + version + ". You may need to upgrade your installation of HomeBridge.");
}
// figure out the main module - index.js unless otherwise specified
var main = pjson.main || "./index.js";
var mainPath = path.join(this.pluginPath, main);
// try to require() it and grab the exported initialization hook
this.initializer = require(mainPath);
}
@@ -69,11 +69,11 @@ Plugin.loadPackageJSON = function(pluginPath) {
// check for a package.json
var pjsonPath = path.join(pluginPath, "package.json");
var pjson = null;
if (!fs.existsSync(pjsonPath)) {
throw new Error("Plugin " + pluginPath + " does not contain a package.json.");
}
try {
// attempt to parse package.json
pjson = JSON.parse(fs.readFileSync(pjsonPath));
@@ -81,7 +81,7 @@ Plugin.loadPackageJSON = function(pluginPath) {
catch (err) {
throw new Error("Plugin " + pluginPath + " contains an invalid package.json. Error: " + err);
}
// make sure the name is prefixed with 'homebridge-'
if (!pjson.name || pjson.name.indexOf('homebridge-') != 0) {
throw new Error("Plugin " + pluginPath + " does not have a package name that begins with 'homebridge-'.");
@@ -91,7 +91,7 @@ Plugin.loadPackageJSON = function(pluginPath) {
if (!pjson.keywords || pjson.keywords.indexOf("homebridge-plugin") == -1) {
throw new Error("Plugin " + pluginPath + " package.json does not contain the keyword 'homebridge-plugin'.");
}
return pjson;
}
@@ -119,9 +119,10 @@ Plugin.getDefaultPaths = function() {
} else {
paths.push('/usr/local/lib/node_modules');
paths.push('/usr/lib/node_modules');
const exec = require('child_process').execSync;
paths.push(exec('/bin/echo -n "$(npm -g prefix)/lib/node_modules"').toString('utf8'));
}
}
return paths;
}
@@ -138,17 +139,17 @@ Plugin.installed = function() {
var plugins = [];
var pluginsByName = {}; // don't add duplicate plugins
var searchedPaths = {}; // don't search the same paths twice
// search for plugins among all known paths, in order
for (var index in Plugin.paths) {
var requirePath = Plugin.paths[index];
// did we already search this path?
if (searchedPaths[requirePath])
continue;
searchedPaths[requirePath] = true;
// just because this path is in require.main.paths doesn't mean it necessarily exists!
if (!fs.existsSync(requirePath))
continue;
@@ -158,17 +159,19 @@ Plugin.installed = function() {
// does this path point inside a single plugin and not a directory containing plugins?
if (fs.existsSync(path.join(requirePath, "package.json")))
names = [""];
// read through each directory in this node_modules folder
for (var index2 in names) {
var name = names[index2];
// reconstruct full path
var pluginPath = path.join(requirePath, name);
// we only care about directories
if (!fs.statSync(pluginPath).isDirectory()) continue;
try {
// we only care about directories
if (!fs.statSync(pluginPath).isDirectory()) continue;
} catch (e) {
continue;
}
// does this module contain a package.json?
var pjson;
try {
@@ -180,14 +183,14 @@ Plugin.installed = function() {
if (!name || name.indexOf('homebridge-') == 0) {
log.warn(err.message);
}
// skip this module
continue;
}
// get actual name if this path points inside a single plugin
if (!name) name = pjson.name;
// add it to the return list
if (!pluginsByName[name]) {
pluginsByName[name] = pluginPath;
@@ -198,6 +201,6 @@ Plugin.installed = function() {
}
}
}
return plugins;
}
+66 -17
View File
@@ -15,6 +15,8 @@ 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");
var chalk = require('chalk');
'use strict';
@@ -22,7 +24,9 @@ module.exports = {
Server: Server
}
function Server(insecureAccess) {
function Server(insecureAccess, opts) {
opts = opts || {};
// Setup Accessory Cache Storage
accessoryStorage.initSync({ dir: User.cachedAccessoryPath() });
@@ -40,16 +44,21 @@ 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._config = opts.config || this._loadConfig();
this._cachedPlatformAccessories = this._loadCachedPlatformAccessories();
this._bridge = this._createBridge();
this._activeDynamicPlugins = {};
this._configurablePlatformPlugins = {};
this._publishedCameras = {};
this._setupManager = new BridgeSetupManager();
this._setupManager.on('newConfig', this._handleNewConfig.bind(this));
this._setupManager.on('requestCurrentConfig', function(callback) {
callback(this._config);
}.bind(this));
@@ -88,15 +97,26 @@ Server.prototype._publish = function() {
// pull out our custom Bridge settings from config.json, if any
var bridgeConfig = this._config.bridge || {};
var info = this._bridge.getService(Service.AccessoryInformation);
if (bridgeConfig.manufacturer)
info.setCharacteristic(Characteristic.Manufacturer, bridgeConfig.manufacturer);
if (bridgeConfig.model)
info.setCharacteristic(Characteristic.Model, bridgeConfig.model);
if (bridgeConfig.serialNumber)
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,
port: bridgeConfig.port || 0,
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) {
@@ -150,12 +170,13 @@ Server.prototype._loadConfig = function() {
// Complain and exit if it doesn't exist yet
if (!fs.existsSync(configPath)) {
log.warn("config.json (%s) not found.", configPath);
var config = {};
config.bridge = {
"name": "Homebridge",
"username": "CC:22:3D:E3:CE:30",
"port": 51826,
"pin": "031-45-154"
};
@@ -409,7 +430,7 @@ Server.prototype._handleRegisterPlatformAccessories = function(accessories) {
accessory._prepareAssociatedHAPAccessory();
hapAccessories.push(accessory._associatedHAPAccessory);
this._cachedPlatformAccessories.push(accessory);
}
@@ -444,6 +465,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 " + accessory.displayName + " experienced an address collision.");
} 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 = [];
@@ -466,8 +515,8 @@ Server.prototype._handleNewConfig = function(type, name, replace, config) {
this._config.accessories.push(config);
} else {
var targetName;
if (name.indexOf('.') == -1) {
targetName = name.split(".")[1];
if (name.indexOf('.') !== -1) {
targetName = name.split(".")[1];
}
var found = false;
for (var index in this._config.accessories) {
@@ -498,8 +547,8 @@ Server.prototype._handleNewConfig = function(type, name, replace, config) {
this._config.platforms.push(config);
} else {
var targetName;
if (name.indexOf('.') == -1) {
targetName = name.split(".")[1];
if (name.indexOf('.') !== -1) {
targetName = name.split(".")[1];
}
var found = false;
@@ -532,9 +581,9 @@ Server.prototype._handleNewConfig = function(type, name, replace, config) {
// Returns the setup code in a scannable format.
Server.prototype._printPin = function(pin) {
console.log("Scan this code with your HomeKit App on your iOS device to pair with Homebridge:");
console.log("\x1b[30;47m%s\x1b[0m", " ");
console.log("\x1b[30;47m%s\x1b[0m", " ┌────────────┐ ");
console.log("\x1b[30;47m%s\x1b[0m", " │ " + pin + " │ ");
console.log("\x1b[30;47m%s\x1b[0m", " └────────────┘ ");
console.log("\x1b[30;47m%s\x1b[0m", " ");
console.log(chalk.black.bgWhite(" "));
console.log(chalk.black.bgWhite(" ┌────────────┐ "));
console.log(chalk.black.bgWhite(" │ " + pin + " │ "));
console.log(chalk.black.bgWhite(" └────────────┘ "));
console.log(chalk.black.bgWhite(" "));
}
+18
View File
@@ -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();
};
+3 -3
View File
@@ -1,7 +1,7 @@
{
"name": "homebridge",
"description": "HomeKit support for the impatient",
"version": "0.3.2",
"version": "0.4.21",
"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.2.8",
"hap-nodejs": "0.4.26",
"semver": "5.0.3",
"node-persist": "^0.0.8"
}